Поскольку определение operator<<
вне класса на самом деле шаблон функции, тогда как объявление друга внутри класса не является шаблоном функции.
Объявление friend
являетсяне шаблонная функция, и ее аргументы фиксированы относительно шаблона класса.
Например, если вы создаете экземпляр шаблона класса с помощью int
, friend
становится следующим:
friend ostream& operator << (ostream& out, const LinkedList<int>& that);
, который сообщает компилятору, что "Я друг этого класса, я также не шаблонная функция, и вы найдете мое определение вне класса, точно с такой же сигнатурой.". Вы можете видеть, что аргументы исправлены.
Но когда вы делаете что-то вроде этого:
template <typename U>
friend ostream& operator << (ostream& out, const LinkedList<U>& that);
Это имеет смысл для компилятора, так как это согласуется с определением operator<<
вне класса, который также является шаблоном функции.Но есть проблема: он делает каждую специализацию шаблона функции другом класса;означает, что когда U=float
, operator<<
может также получить доступ к закрытым членам LinkedList<int>
, тогда как он должен иметь доступ только к закрытым членам LinkedList<float>
.Итак, вы видите, что это проблема.
Лучшее решение было бы так: НЕ делайте его функциональным шаблоном и не определяйте друга внутри самого класса.
template<typename T>
class LinkedList
{
public:
friend ostream& operator << (ostream& out, const LinkedList<T>& that)
{
//definition
}
};