Question

How can I make the insertion (<<) and/or extraction (>>) operator overloaded in a template class WITHOUT making it inline. I would like to have the << or >> operator as a friend class. I know how to make it inline example of inline in a matrix class

friend ostream& operator<<(ostream& ostr, const Matrix<T>& inputMatrix)
{
   ...
   // create the ostr
   return ostr;
}

but I'd like to have the code outside of the templateclass definition.

g++ told me to add <> after the function name so I did but when I tried to instansiate a matrix of type SOMETYPE it gave me an error that it didn't know how to extract or insert for that type.

Was it helpful?

Solution

If you really want to define the operator externally and befriend only the operator instantiation that coincides in type with this template instantiation, the correct syntax is:

template <typename T> class test; // forward declare template class
template <typename T>              // forward declare the templated operator
std::ostream& operator<<( std::ostream&, test<T> const & );

template <typename T>
class test {                      // define the template
   friend std::ostream& operator<< <T>( std::ostream&, test<T> const & ); // befriend
};
template <typename T>              // define the operator 
std::ostream& operator<<( std::ostream& o, test<T> const & ) {
   return o;
}

In most cases it is not worth the hassle to pull the definition out of the class, considering that you still need to provide it in a header and the extra work required.

Also note that there are slight differences for the compiler regarding lookup. In the case where the function is inlined inside the class definition, the compiler will not find that function unless one of the arguments is actually of the type of the template, so it effectively reduces the visibility and the amount of work that the compiler has to do (if the templated operator<< is defined outside of the class, the compiler will find it as a candidate for overload resolution in all places where it finds a << b, only to discard it in all cases where the second argument is not a test<T> (and it will show the templated operator as a candidate in all error messages where it cannot match operator<<, which is a long enough list already).

OTHER TIPS

Try something like:

template <typename T> class Matrix;
template <typename T> std::ostream& operator<<(std::ostream& ostr, const Matrix<T>& m);

template <Typename T>
class Matrix
{
    public:

        friend ostream& operator<< <T> (ostream& ostr, const Matrix<K>& inputMatrix);
};

// This must be in the same translation unit as the class definition!
template<typename T>
ostream& operator<<(ostream& ostr, const Matrix<T>& inputMatrix)
{
   // ...
   return ostr;
}

Translation unit reference

re-re-edited to addressed the comments made by aschepler and dribeas.

Place the code in the header, outside the class definition. Or, place it in a .tcc file and include it at the bottom of the header.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top