Естественно, у шаблона могут быть друзья, и шаблоны тоже могут быть друзьями, но тут тоже имеют место некоторые нюансы (см. п. п. 14.5.3 в [1]). Напишем простейший шаблонный класс и определим для него дружественную операцию вывода <<. Во-первых, выясняется, что дружественная функция должна быть шаблоном, так как аргумент для вывода у нее, очевидно, зависит от параметра шаблонного класса. Во-вторых, шаблонность операции надо как-то указать в шаблонном классе. Как это делается, показано в листинге 11.14.
Листинг 11.14. Дружественная функция-шаблон
#include <iostream> template <typename T> class Tclass { T x; public:
Tclass(const T &t): x(t) {} // конструктор инициапизации
friend std::ostream& operator<< <>(std::ostream &os, const Tclass<T> &t);
};
// внешнее определение функции-шаблона template<class T>
std::ostream& operator<<(std::ostream &os, const Tclass<T>&t) { return os << '(' << t.x << ')'; }
Определение дружественной функции-шаблона похоже на определение метода-шаблона, но несколько проще — нет второго заголовка. На то, что дружественная операция является шаблоном, указывают пустые скобки <> после имени функции в прототипе, задаваемом в определении класса.
Внешние определения дружественных функций-шаблонов имеют одну существенную особенность: автоматические преобразования аргументов не выполняются. Включим в наш пример дружественную операцию сложения — тогда наш шаблон будет выглядеть так, как показано в листинге 11.15.
Подробности определения шаблонов функций рассматриваются в следующей главе.
Листинг 11.15. Дружественная функция сложения
#include <iostream> template <typename T> class Tclass { T x; public: Tclass(const T &t):x(t) {}
friend std::ostream& operator<< <>(std::ostream &os, const Tclass<T> &t): friend Tclass<T> operator+ <>(const Tclass<T>&a, const Tclass<T>&b);
}:
template<class T>
std::ostream& operator<<(std::ostream &os, const Tclass<T>&t) { return os << '(' << t.x << ')'; } template<class T>
Tclass<T> operator+(const Tclass<T>&a, const Tclass<T>&b) { return Tclass<T>(a.x + b.x): }
Попробуем использовать эти шаблоны:
Tclass<int> а(1). dl(2), d2(3): cout << a << endl: cout << dl+d2 << endl:
cout << dl+1 << endl; // ошибка компиляции!
Выражение dl+1 вызывает ошибку компиляции — оказывается, для шаблонов конструктор автоматически не вызывается, как это делается для обычных классов. Решение состоит в том, чтобы определить дружественные функции непосредственно внутри класса (листинг 11.16). |