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.

 

posted @ 2012-09-20 19:53  walfud  阅读(205)  评论(0编辑  收藏  举报