The << (ostream & os, ...) operator for the template class

Why can't I use the same template parameter for a friend function that takes a template argument? I mean the code below is ok!

 template <class Vertex> class Edge { template <class T> friend ostream& operator<<(ostream& os, const Edge<T>& e); /// ... }; template <class T> ostream& operator<<(ostream& os, const Edge<T>& e) { return os << e.getVertex1() << " -> " << e.getVertex2(); } 

But this is not normal. What for? What is the problem? (I get a linker error.)

 template <class Vertex> class Edge { friend ostream& operator<<(ostream& os, const Edge<Vertex>& e); /// ... }; template <class T> ostream& operator<<(ostream& os, const Edge<T>& e) { return os << e.getVertex1() << " -> " << e.getVertex2(); } 
+6
source share
4 answers

You can use the following

 template <class Vertex> class Edge { friend ostream& operator<< <>(ostream& os, const Edge<Vertex>& e); /// ... }; 

which makes operator << <Vertex> friend for Edge .

In your second case, you create a friendly operator statement without a template, but the definition of this operator is a template, so you have an undefined reference, but this case can be used if you want your operator << for a specific Edge ( Edge<int> eg).

+3
source
 template <class T> friend ostream& operator<<(ostream& os, const Edge<T>& e); 

He says that there is a templated operator << outside, be friends with him, and everything is in order.

  friend ostream& operator<<(ostream& os, const Edge<Vertex>& e); 

Says that there is operator << outside, be friends with it ... and the compiler cannot find such a thing.

To tell the compiler that the template is a template, help it with <> , as indicated in ForEveR (it quickly beat me: -D).

+2
source

The problem is that here:

 friend ostream& operator<<(ostream& os, const Edge<Vertex>& e); 

You declare a function without a template (which will be different for each Edge instance) as a friend , and not create a template.

The most common solution I saw was to simply embed the operator<< built-in string in the class definition template. In addition, you can provide a public member function that outputs and is called from the operator<< function template. Or you can write:

 friend ostream& operator<< <Vertex>(ostream&, Edge<Vertex> const& ); 

to tell the compiler that operator<< , which is a friend, is creating a template. IIUC, however, this only works if there is an declaration of the objective function operator<< At this point, the template is displayed, which means that you need to forward declare it (and in order to direct it, forward declare the class template).

My usual solution for this kind of task is to provide a normal print member function, and then infer from:

 template <typename DerivedType> class IOStreamOperators { public: friend std::ostream&operator<<( std::ostream& dest, DerivedType const& source ) { source.print( dest ) ; return dest ; } friend std::istream&operator>>( std::istream& source, DerivedType& dest ) { dest.scan( source ) ; return source ; } protected: ~IOStreamOperators() {} }; 

eg:

 template <class Vertex> class Edge : public IOStreamOperators<Edge<Vertex> > { // ... void print( std::ostream& dest ) { // ... } }; 

I found that this makes the code simpler and easier to follow at the end.

+2
source

I think it’s easiest to understand if we remove extraneous noise and consider:

 template <typename T> struct X { friend void f(X<T>& x) { } }; template <typename T> void f(const X<T>& x) { } 
  • f inside X : void f(X<T>& x)
  • f outside X : void f<T>(X<T>& x)

You can get a hint of this by compiling and looking at the generated characters:

 00410aa8 t .text$_Z1fR1XIdE 00410ad4 t .text$_Z1fIdEvRK1XIT_E 

GCC call __ PRETTY_FUNCTION __ from each output:

 void f(X<double>&) void f(const X<T>&) [with T = double] 

Not entirely clear, but GCC is the way to say the last void f<double>(...) .

Personally for templates, I tend to define a function in a class ... you don't need to mention this template, just:

 friend ostream& operator<<(ostream& os, const Edge& e) { // use e.whatever... } 
+1
source

All Articles