Недавно столкнулся с такой проблемой как осложнение operator<<
для template class
, и вот ищя ответ на этот вопрос, перерыл много вопросов на английском stack'e. Нашёл решение вот тут. Меня смутило такое решение проблемы -
template <typename T>
class Test {
template <typename U> // all instantiations of this template are my friends
friend std::ostream& operator<<( std::ostream&, const Test<U>& );
};
template <typename T>
std::ostream& operator<<( std::ostream& o, const Test<T>& ) {
// Can access all Test<int>, Test<double>... regardless of what T is
}
Я не понимаю почему тут используется совсем другой template
- template <typename U>
, а тут такой template <typename T>
.
Вроде как пытался перевести, но так и не понял. А может я не совсем понимаю работы friend
?
На самом деле нет никакой разницы между template <typename T>
, template <typename U>
, template <class A>
и template <class BestTypeEver>
. Это просто псевдоним для типа, который будет выведен компилятором во время компиляции. Так что можете заменить эти имена так чтобы они вас не смущали:
template <typename T>
class Test {
template <typename U> // all instantiations of this template are my friends
friend std::ostream& operator<<( std::ostream&, const Test<U>& );
};
template <typename U>
std::ostream& operator<<( std::ostream& o, const Test<U>& ) {
// Can access all Test<int>, Test<double>... 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;
}
Во-первых, как вам же ответили, шаблонный параметр - это лишь локальный формальный параметр, имя которого не имеет никакого значения. В точке friend-объявления оператора вы не можете использовать имя T
, так как оно уже "занято" охватывающим шаблоном. А в точке определения оператора имя T
свободно и его можно использовать.
Однако, во-вторых, стоит заметить, что в данном случае вы наблюдаете то, что можно назвать "ленивым" вариантом friend-объявления. Этот вариант более компактен, но в то же время формально избыточен, ибо он объявляет все специализации оператора <<
друзьями всех специализаций класса Test
. В частности operator << <int>
будет являться другом класса Test<double>
. (Именно об этом написано в комментарии внутри определения оператора.)
В такой избыточной "перекрестной дружбе" нет ничего плохого или опасного, однако если она вам не нужна и вы хотите поступить более педантично, т.е сделать так, чтобы каждая специализация оператора дружила именно и только со "своей" специализацией шаблона класса Test
, то писанины будет чуть побольше
template <typename>
class Test;
template <typename T>
std::ostream& operator<<( std::ostream& o, const Test<T>& );
template <typename T>
class Test {
friend std::ostream& operator<< <>( std::ostream&, const Test& );
};
template <typename T>
std::ostream& operator<<( std::ostream& o, const Test<T>& ) {
// Can access only Test<T>
}
Именно из-за несколько большей громоздкости такого педантичного варианта зачастую некоторые авторы предпочитают прибегать к "ленивому" варианту.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
В целом, я даже не уверен ещё правильно ли освобождаю память, и освобождается ли она вообщено на запуске дебаггер ругается именно на этот...
Имеется класс MyClass, разумеется с конструктором, нужно создать вектор умных указателей на объекты этого классаСам указатель создается, но при...