Reputation: 43
I want to write a friend function for a template class. In visual studio, I can ignore the pre-definition both. But in g++, it is mandatory. Why?
#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;
}
Upvotes: 2
Views: 91
Reputation: 275760
MSVC template code is fundamantally broken. They have been rebuilding it over the last few years, but it still contains quirks like what you are observing. This is because it was built to be almost macro like, instead of being what the C++ standard required.
In gcc you can do away with the forward declarations by defining the <<
operator inline in the body of the class:
friend std::ostream& operator<<(std::ostream& c, const A& v){
c << v._v;
return c;
}
this has the advantage that <<
becomes no longer a template
, but rather a distinct non-template created for each instance of the template A
. In some scenarios this tends to work better.
Upvotes: 0
Reputation: 16109
Because
friend ostream & operator<<<T>(ostream & c, const A<T> & v);
is a specialization of
template <class T>
ostream & operator<<(ostream & c, const A<T> & v);
you need to declare that first and the
A<T>
part means you have to declare that too before the operator declaration
template <class T>
class A;
So VS is probably wrong as C++14
14.5.4 Friends [temp.friend]
gives the example
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;
};
Where your example fits the 3rd friend declaration.
Upvotes: 2