Ошибка компоновщика шаблонов в функции друга

При изучении шаблонов я столкнулся со следующими упражнениями:

#include <iostream>
using namespace std;
template <class T>
class A {
    T _v;
public:
    A() {}
    A(T v) : _v(v) {}
    friend ostream & operator<<(ostream & c, const A<T> & v);
};

template <class T>
ostream & operator<<(ostream & c, const A<T> & v){
    c << v._v; return c;
}

int main()
{
    A<int>a(10);
    cout << a << endl;
    return 0;
}

Этот фрагмент кода должен выдавать ошибку во время компиляции, и это действительно так. Это ошибка компоновщика, но я не могу этого понять.

Я попытался изменить несколько строк кода, и ошибка, похоже, вызвана установкой шаблона operator<<, поскольку удаление этого шаблона и написание определенного оператора заставляют код работать. У меня также есть ощущение, что шаблон создается несколько раз, а не только для int.

Однако, насколько мне известно, определение шаблона выглядит нормально. Что мне не хватает?

Точная ошибка (VS 2017): Ошибка LNK2019: неразрешенный внешний символ "класс std::basic_ostream > & __cdecl operator‹‹ (класс std::basic_ostream > &, class A const &)" (??6@YAEAAV?$ basic_ostream@DU?$char_traits@D@std@@@std@@AEAV01@AEBV?$A@H@@@Z) упоминается в функции main


person Andrea Bocco    schedule 03.02.2019    source источник
comment
А ошибка есть?   -  person Matthieu Brucher    schedule 03.02.2019
comment
Параметр шаблона не наследуется от объявления дружественной функции. Я постараюсь найти дубликат.   -  person πάντα ῥεῖ    schedule 03.02.2019


Ответы (1)


Вам нужно объявить функцию друга как шаблон:

class A {
   ...
   template <class U>  // <-- NOTICE ---------------v
   friend ostream & operator<<(ostream & c, const A<U> & v);
   ...

Или, что еще лучше, используйте более безопасный подход, хотя и немного более подробный:

#include <iostream>
using namespace std;

template <class T>
class A;

template <class T>
ostream& operator<<(ostream& c, const A<T>& v);

template <class T>
class A {
    T _v;

    public:
    A() {}
    A(T v) : _v(v) {}
    friend ostream& operator<< <T>(ostream& c, const A<T>& v);
};

template <class T>
ostream& operator<<(ostream& c, const A<T>& v) {
    c << v._v;
    return c;
}

int main() {
    A<int> a(10);
    cout << a << endl;
    return 0;
}

Дополнительные сведения см. на этой странице.

person iBug    schedule 03.02.2019