C++ : friend declaration ‘declares a non-template function

Vincent picture Vincent · May 28, 2012 · Viewed 9.1k times · Source

I have a problem to overload the << stream operator and I don't find the solution :

template<class T, unsigned int TN>
class NVector
{
    inline friend std::ostream& operator<< (
        std::ostream &lhs, const NVector<T, TN> &rhs);
};

template<class T, unsigned int TN>
inline std::ostream& NVector<T, TN>::operator<<(
    std::ostream &lhs, const NVector<T, TN> &rhs)
{
    /* SOMETHING */
    return lhs;
};

It produces the following error message:

warning : friend declaration ‘std::ostream& operator<<(std::ostream&, const NVector&)’ declares a non-template function [-Wnon-template-friend]

error: ‘std::ostream& NVector::operator<<(std::ostream&, const NVector&)’ must take exactly one argument

How to solve that problem ?

Thank you very much.

Answer

David Rodr&#237;guez - dribeas picture David Rodríguez - dribeas · May 28, 2012

There are two different issues in your code, the first is that the friend declaration (as the warning clearly says, maybe not so clear to understand) declares a single non-templated function as a friend. That is, when you instantiate the template NVector<int,5> it declares a non-templated function std::ostream& operator<<(std::ostream&,NVector<int,5>) as a friend. Note that this is different from declaring the template function that you provided as a friend.

I would recommend that you define the friend function inside the class definition. You can read more on this in this answer.

template <typename T, unsigned int TN>
class NVector {
   friend std::ostream& operator<<( std::ostream& o, NVector const & v ) {
      // code goes here
      return o;
   }
};

Alternatively you can opt for other options:

  1. declare the operator<< template as a friend (will grant access to any and all instantiations of the template),
  2. declare a particular instantiation of that template as a friend (more cumbersome to write) or
  3. avoid friendship altogether providing a public print( std::ostream& ) member function and calling it from a non-friend templated operator<<. I would still opt to befriend the non-template function an provide the definition inside the templated class.

The second issue is that when you want to define an operator outside of the class of the left hand side argument, the operator is a free function (not bound to a class) and thus it should not be qualified:

template<class T, unsigned int TN>
inline std::ostream& operator<<(std::ostream &lhs, const NVector<T, TN> &rhs)
{
    /* SOMETHING */
    return lhs;
};