Страницы

Поиск по вопросам

пятница, 13 декабря 2019 г.

Различные имена типа в объявлении и определении шаблонной функции

#cpp #классы #шаблоны_с++


Недавно столкнулся с такой проблемой как осложнение operator<< для template class,
и вот ищя ответ на этот вопрос, перерыл много вопросов на английском stack'e. Нашёл
решение вот тут. Меня смутило такое решение проблемы -

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 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 } Именно из-за несколько большей громоздкости такого педантичного варианта зачастую некоторые авторы предпочитают прибегать к "ленивому" варианту.

Комментариев нет:

Отправить комментарий