Search code examples
c++templatesfriend-function

How to split the definition of template friend function within template class?


The following example compiles fine but I can't figure out how to separate declaration and definition of operator<<() is this particular case.

Every time I try to split the definition friend is causing trouble and gcc complains the operator<<() definition must take exactly one argument.

#include <iostream>
template <typename T>
class Test {
    public:
        Test(const T& value) : value_(value) {}

        template <typename STREAM>
        friend STREAM& operator<<(STREAM& os, const Test<T>& rhs) {
            os << rhs.value_;
            return os;
        }
    private:
        T value_;
};

int main() {
    std::cout << Test<int>(5) << std::endl;
}

Operator<<() is supposed to have a free first parameter to work with different kind of output streams (std::cout, std::wcout or boost::asio::ip::tcp::iostream). The second parameter should be bound to a specialized version of the surrounding class.

Test<int> x;
some_other_class y;

std::cout << x; // works
boost::asio::ip::tcp::iostream << x; // works

std::cout << y; // doesn't work
boost::asio::ip::tcp::iostream << y; // works

Besides that using a non-member-function isn't equivalent to splitting the definition and declaration because non-member-functions can't access private attributes the the class.


Solution

  • The easiest is probably to make all these template operators friends:

    #include <iostream>
    template <typename T>
    class Test
    {
        public:
            Test(const T& value) : value_(value) {}
    
            template <typename STREAM, typename U>
            friend STREAM& operator<<(STREAM& os, const Test<U>& rhs);
    
        private:
            T value_;
    };
    
    template <typename STREAM, typename T>
    STREAM& operator<<( STREAM& os, const Test<T>& rhs )
    {
        os << rhs.value_;
        return os;
    }