c++templatesfriendostream

Friend function in a template class for operator<<


What is the correct way to declare a friend function of a template class (for the std::ostream& operator<<) in a .cpp file ?

My current implementation does not work :

// MyTest.h
template<class T, unsigned int TSIZE> class MyTest
{
    inline friend std::ostream& operator<< <T, TSIZE> (std::ostream &lhs, const MyTest<T, TSIZE> &rhs);
};

// MyTest.cpp
template<class T, unsigned int TSIZE> inline friend std::ostream& operator<< <T, TSIZE> (std::ostream &lhs, const MyTest<T, TSIZE> &rhs)
{
    // IMPLEMENTATION
}

Solution

  • To refer to operator<< <T, TSIZE> like you do, which is a template specialization, a declaration of the primary template must be visible. In turn operator<< needs a declaration of MyTest because it appears as a parameter.

    // Declare MyTest because operator<< needs it
    template<class T, unsigned int TSIZE> class MyTest;
    
    // Declare primary template
    template<class T, unsigned int TSIZE>
    inline std::ostream& operator<<(std::ostream& lhs, const MyText<T, TSIZE>& rhs);
    
    template<class T, unsigned int TSIZE> class MyTest
    {
        // Specialization MyTest<T, TSIZE> only declares
        // specialization operator<< <T, TSIZE> as friend
        // Note that you can just use '<>' to designate the specialization,
        // template parameters are deduced from the argument list in this case
        inline friend std::ostream& operator<< <> (std::ostream &lhs, const MyTest<T, TSIZE> &rhs);
    };
    

    The definition you have should match those declarations. Note that since operator<< is a template its definition should in all likeliness be in the header.

    An alternative that requires less work when it comes to writing all those preemptive declarations is for MyTest<T, TSIZE> to declare the whole template as a friend, not just the specialization that takes MyTest<T, TSIZE>.

    // in MyTest definition
    template<typename U, unsigned USIZE>
    inline friend std::ostream& operator<<(std::ostream& lhs, const MyTest<U, USIZE>& rhs);
    

    The definition you have should also match such a declaration (the name of the template parameters has no bearing on matching declarations and definition).

    For the sake of completeness, I will mention that when it comes to the friend of a class template an alternative is to define it in the class template definition. This defines a non-template friend function that is unique for each specialization.

    // in MyTest definition
    friend std::ostream& operator<<(std::ostream& lhs, MyTest const& rhs)
    { /* implementation */ }
    

    It is impossible to refer to such functions (e.g. &ns::operator<< doesn't work, unlike the other options) and they are only found via ADL.