为什么 g++ 需要模板 class 及其友元函数的定义?

why does g++ need both definitions of template class and its friend function?

我想为模板编写友元函数class。 在visual studio中,我可以忽略预定义两者。 但在 g++ 中,它是强制性的。 为什么?

#include <iostream>
using namespace std;
// g++ needs, vs do not needs
template <class T>
class A;

template <class T>
ostream & operator<<(ostream & c, const A<T> & v);
//- end of g++ needs

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;
}

因为

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

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

你需要先声明,然后

A<T>

部分意味着您必须在运算符声明之前也声明它

template <class T>
class A;

所以VS可能是错的C++14

14.5.4 Friends [temp.friend] 

举个例子

template<class T> class task;
template<class T> task<T>* preempt(task<T>*);

template<class T> class task {
  friend void next_time();
  friend void process(task<T>*);
  friend task<T>* preempt<T>(task<T>*);
  template<class C> friend int func(C);

  friend class task<int>;
  template<class P> friend class frd;
};

你的例子符合第三个朋友声明。

MSVC 模板代码从根本上被破坏了。他们在过去几年一直在重建它,但它仍然包含您所观察到的怪癖。这是因为它被构建为几乎类似于宏,而不是 C++ 标准所要求的。

在 gcc 中,您可以通过在 class:

的主体中内联定义 << 运算符来取消前向声明
friend std::ostream& operator<<(std::ostream& c, const A& v){
  c << v._v;
  return c;
}

这样做的好处是 << 不再是 template,而是为模板 A 的每个实例创建的独特的非模板。在某些情况下,这往往会更好。