#cpp #классы #шаблоны_с++
Недавно столкнулся с такой проблемой как осложнение operator<< для template class, и вот ищя ответ на этот вопрос, перерыл много вопросов на английском stack'e. Нашёл решение вот тут. Меня смутило такое решение проблемы - templateclass Test { template // all instantiations of this template are my friends friend std::ostream& operator<<( std::ostream&, const Test& ); }; template std::ostream& operator<<( std::ostream& o, const Test & ) { // Can access all Test , Test ... regardless of what T is } Я не понимаю почему тут используется совсем другой template - template , а тут такой template . Вроде как пытался перевести, но так и не понял. А может я не совсем понимаю работы friend?
Ответы
Ответ 1
На самом деле нет никакой разницы между template, template , template и template . Это просто псевдоним для типа, который будет выведен компилятором во время компиляции. Так что можете заменить эти имена так чтобы они вас не смущали: template class Test { template // all instantiations of this template are my friends friend std::ostream& operator<<( std::ostream&, const Test& ); }; template std::ostream& operator<<( std::ostream& o, const Test& ) { // Can access all Test , Test ... regardless of what U is } Что касается friend, это ключевое слово говорит то том, что ваш оператор << может обращаться к приватным и защищенным членам класса. class A{ int _privateMember; friend std::ostream& operator<<( std::ostream& o, const A& a); } std::ostream& operator<<( std::ostream& o, const A& a){ o << a._privateMember; //так можно только благодаря friend return o; } Строго говоря, если вы можете добраться до всего что вам нужно через открытый интерфейс, то можно обойтись и без friend: class A{ int _privateMember; public: int getPrivateMember() const{ return _privateMember; } } std::ostream& operator<<( std::ostream& o, const A& a){ o << a.getPrivateMember(); return o; } Ответ 2
Во-первых, как вам же ответили, шаблонный параметр - это лишь локальный формальный параметр, имя которого не имеет никакого значения. В точке friend-объявления оператора вы не можете использовать имя T, так как оно уже "занято" охватывающим шаблоном. А в точке определения оператора имя T свободно и его можно использовать. Однако, во-вторых, стоит заметить, что в данном случае вы наблюдаете то, что можно назвать "ленивым" вариантом friend-объявления. Этот вариант более компактен, но в то же время формально избыточен, ибо он объявляет все специализации оператора << друзьями всех специализаций класса Test. В частности operator <<будет являться другом класса Test . (Именно об этом написано в комментарии внутри определения оператора.) В такой избыточной "перекрестной дружбе" нет ничего плохого или опасного, однако если она вам не нужна и вы хотите поступить более педантично, т.е сделать так, чтобы каждая специализация оператора дружила именно и только со "своей" специализацией шаблона класса Test, то писанины будет чуть побольше template class Test; template std::ostream& operator<<( std::ostream& o, const Test & ); template class Test { friend std::ostream& operator<< <>( std::ostream&, const Test& ); }; template std::ostream& operator<<( std::ostream& o, const Test & ) { // Can access only Test } Именно из-за несколько большей громоздкости такого педантичного варианта зачастую некоторые авторы предпочитают прибегать к "ленивому" варианту.
Комментариев нет:
Отправить комментарий