Оператор Overloading <<для шаблонного класса

5
задан David Rodríguez - dribeas 28 November 2009 в 11:46
поделиться

4 ответа

Проблема в том, что компилятор пытается использовать не шаблонный оператор << , который вы указали, а скорее не шаблонную версию.

Когда вы объявляете friend внутри класса, вы вводите объявление этой функции во включающую область. Следующий код имеет эффект объявления (а не определения) свободной функции, которая принимает аргумент non_template_test по постоянной ссылке:

class non_template_test
{
   friend void f( non_template_test const & );
};
// declares here:
// void f( non_template_test const & ); 

То же самое происходит с шаблонными классами, даже если в данном случае это немного менее интуитивно понятный. Когда вы объявляете (а не определяете) дружественную функцию в теле класса шаблона, вы объявляете бесплатную функцию с этими точными аргументами. Обратите внимание, что вы объявляете функцию, а не функцию-шаблон:

template<typename T>
class template_test
{
    friend void f( template_test<T> const & t );
};
// for each instantiating type T (int, double...) declares:
// void f( template_test<int> const & );
// void f( template_test<double> const & );

int main() {
    template_test<int> t1;
    template_test<double> t2;
}

Эти бесплатные функции объявлены, но не определены. Сложность здесь в том, что эти бесплатные функции не являются шаблоном, а являются объявленными обычными бесплатными функциями. Когда вы добавляете в смесь шаблонную функцию, вы получаете:

template<typename T> class template_test {
   friend void f( template_test<T> const & );
};
// when instantiated with int, implicitly declares:
// void f( template_test<int> const & );

template <typename T>
void f( template_test<T> const & x ) {} // 1

int main() {
   template_test<int> t1;
   f( t1 );
}

Когда компилятор запускает основную функцию, он создает экземпляр шаблона template_test с типом int и объявляет свободную функцию void f (template_test const &) , для которого нет шаблона. Когда он находит вызов f (t1) , обнаруживаются два совпадающих символа f : нешаблонный f (template_test const &) объявлен ( и не определена), когда был создан экземпляр template_test , и шаблонная версия, которая объявлена ​​и определена в 1 . Версия без шаблона имеет приоритет, и компилятор ей соответствует.

Когда компоновщик пытается разрешить нестандартную версию f , он не может найти символ и поэтому терпит неудачу.

Что мы можем сделать? Есть два разных решения. В первом случае мы заставляем компилятор предоставлять не шаблонные функции для каждого типа создания экземпляра. Во втором случае мы объявляем шаблонную версию своим другом. Они немного отличаются, но в большинстве случаев эквивалентны.

Если компилятор генерирует для нас не шаблонные функции:

template <typename T>
class test 
{
   friend void f( test<T> const & ) {}
};
// implicitly

Это дает эффект создания необходимого количества бесплатных не шаблонных функций. Когда компилятор находит объявление друга в шаблоне test , он находит не только объявление, но и реализацию, и добавляет их в охватывающую область.

Сделать шаблонную версию другом

Чтобы сделать шаблон другом, мы должны уже объявить его и сообщить компилятору, что нужный нам друг на самом деле является шаблоном, а не свободной функцией без шаблона:

template <typename T> class test; // forward declare the template class
template <typename T> void f( test<T> const& ); // forward declare the template
template <typename T>
class test {
   friend void f<>( test<T> const& ); // declare f<T>( test<T> const &) a friend
};
template <typename T> 
void f( test<T> const & ) {}

В В этом случае, прежде чем объявить f в качестве шаблона, мы должны переслать объявление шаблона. Чтобы объявить шаблон f , мы должны сначала объявить тестовый шаблон . Объявление друга изменено, чтобы включить угловые скобки, которые указывают, что элемент, который мы делаем другом, на самом деле является шаблоном, а не бесплатной функцией.

Вернуться к проблеме

Возвращаясь к вашему конкретному примеру, простейшее решение заставляет компилятор генерировать функции для вас, вставляя объявление функции друга:

8
ответ дан 18 December 2019 в 09:50
поделиться

you dont need the template operator declaration and you have to declare the operator "friend" for your class to have granted access to other classes, in this case std::cout

friend std::ostream& operator << ( std::ostream& os, BinaryTree & tree )
{
    doStuff( os, tree );
    return os;
}

recomended reading: http://www.parashift.com/c++-faq-lite/friends.html

4
ответ дан 18 December 2019 в 09:50
поделиться

При перегрузке оператора << вы хотите использовать константную ссылку:

template <class T>
std::ostream& operator << (std::ostream& os, const BinaryTree<T>& tree) 
{
    // output member variables here... (you may need to make
    // this a friend function if you want to access private
    // member variables...

    return os;
}
3
ответ дан 18 December 2019 в 09:50
поделиться

Убедитесь, что определения шаблонов полны (а не только прототипы) находятся во включаемом файле (т.е. .h, .hpp), поскольку шаблоны и отдельная компиляция не работают вместе.

Я не знаю, какой компоновщик использует @Dribeas, но это определенно может привести к тому, что компоновщик GNU выдает неопределенную ошибку ссылки.

2
ответ дан 18 December 2019 в 09:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: