При работе в С++ время от времени приходится создавать свои собственные шаблоны. Их синтаксис описывается в любой более-менее приличной книге по С++. Но правильное объявление дружественной функции может вызвать трудности. Рассмотрим шаблонный класс.
template <class T> class MyClass { T value_; public: MyClass(const T &value) : value_(value) {}; MyClass<T> copy() const { return *this;}; friend bool operator == (const MyClass<T>&, const MyClass<T>&); }; //Сама дружественная функция template <class T> bool operator == (const MyClass<T> &left, const MyClass<T> &right) { return (left.value_ == right.value_); }
Вроде бы все легально. Но при попытке его скомпилировать мы получим сообщение (компилятор g++):
main.cpp:15:66: warning: friend declaration ‘bool operator==(const MyClass<T>&, const MyClass<T>&)’ declares a non-template function [-Wnon-template-friend]
friend bool operator == (const MyClass<T>&, const MyClass<T>&);
g++ ругается на то, что дружественная функция объявлена не как шаблон. Для исправления этого недостатка, объявление класса MyClass нужно переписать так:
template <class T> class MyClass { T value_; public: MyClass(const T &value) : value_(value) {}; MyClass<T> copy() const { return *this;}; template <class V> friend bool operator == (const MyClass<V>&, const MyClass<V>&); };
Теперь все нормально компилируется. Это предпочтительный вариант решения проблемы, но есть и другой.
template <class T> class MyClass { T value_; public: MyClass(const T &value) : value_(value) {}; MyClass<T> copy() const { return *this;}; friend bool operator == (const MyClass<T> &left, const MyClass<T> &right) { return (left.value_ == right.value_); }; };
В данном случае тело функции располагается в месте ее объявления. А как насчет методов класса? В нашем примере тело метода располагается внутри объявления класса. Если бы мы захотели его вынести, нужно было бы написать так:
template <class T> class MyClass { T value_; public: MyClass(const T &value) : value_(value) {}; MyClass<T> copy() const; template <class V> friend bool operator == (const MyClass<V>&, const MyClass<V>&); }; template <class T> MyClass<T> MyClass<T> :: copy() const { return *this; }
Обратите внимание: при объявлении области видимости класса MyClass<T> ключевое слово typename не нужно.