Making New Friends Idiom
#include <iostream> using namespace std; template <typename T> class X { T m_val; public: friend auto operator<<(ostream &o, const X &x) -> ostream &; }; template <typename T> auto operator<<(ostream &o, const X<T> &x) -> ostream & { return o <<x.m_val; } int main(int argc, char *argv[]) { cout <<X<int>() <<endl; return 0; }
This error is says the compiler can't find the definition of 'operator<< <int>'.
We have written a 'template operator<<', and want compiler to generate code for us, but no magic occurs.
The reason why compiler do Not take 'template operator<<' is easy, just because the time binding 'operator<<' by 'friend auto operator<<(...) -> ostream &', the compiler has Not seen any 'template operator<<' yet. Thus, any instantiate of 'class X', the function 'operator<<' is a non-template funcion, it's only a declaration without definition.
Solution but not end:
#include <iostream> using namespace std; template <typename T> class X; template <typename T> auto operator<<(ostream &o, const X<T> &x) -> ostream &; // Declare a template operator<<. template <typename T> class X { T m_val; public: friend auto operator<< <>(ostream &o, const X &x) -> ostream &;// Binding function to the template one // using '<>'. }; template <typename T> // Of coursely you'd define the function. auto operator<<(ostream &o, const X<T> &x) -> ostream & { return o <<x.m_val; } int main(int argc, char *argv[]) { cout <<X<int>() <<endl; // Sunny day, isn't it? return 0; }
Better one:
#include <iostream> using namespace std; //template <typename T> //class X; // //template <typename T> //auto operator<<(ostream &o, const X<T> &x) -> ostream &; // Needless. template <typename T> class X { T m_val; public: friend auto operator<< <>(ostream &o, const X &x) -> ostream &; // Only '<>' added than the problem one. (The first code snippet) }; template <typename T> auto operator<<(ostream &o, const X<T> &x) -> ostream & { return o <<x.m_val; } int main(int argc, char *argv[]) { cout <<X<int>() <<endl; // Also fine. 1) return 0; }
This code looks much lighter.
We does Not declare any 'operator<<' before 'friend auto operator<<....', how does compiler know to binding the function? The answer is: Bacause 'class X' is a template. That is to say, when and only when you write 'X<int>' will the compiler do really generate a specified class (in our code, is 1) ).
Whether you believe it or not, I'll show you a counter-example:
template <typename T> class X { T m_val; public: friend auto operator<< <>(ostream &o, const X &x) -> ostream &; }; bool complain = (X<int>(), true); // Familiar error. template <typename T> auto operator<<(ostream &o, const X<T> &x) -> ostream & { return o <<x.m_val; } int main(int argc, char *argv[]) { cout <<X<int>() <<endl; // Also fine. return 0; }
When intantiate the global variable 'complain', the side effect ('class X' is instatiate) looks for the definition of 'operator<< <int>', which is Not a template and have no definition yet. That's the reason.