Overloading friend operator << for template class [duplicate]
Asked Answered
P

3

28

I'm trying to overload the operator << as a friend to a template class Pair, but I keep getting a compiler warning saying

friend declaration std::ostream& operator<<(ostream& out, Pair<T,U>& v) declares a non template function

for this code:

friend ostream& operator<<(ostream&, Pair<T,U>&);

it gives a second warning as a recommendation saying

if this is not what you intended, make sure the function template has already been declared and add <> after the function name here

Here is the function definition

template <class T, class U>
ostream& operator<<(ostream& out, Pair<T,U>& v)
{
    out << v.val1 << " " << v.val2;
}

and here is the whole class.

template <class T, class U>
class Pair{
public:
    Pair(T v1, U v2) : val1(v1), val2(v2){}
    ~Pair(){}
    Pair& operator=(const Pair&);
    friend ostream& operator<<(ostream&, Pair<T,U>&);

private:
    T val1;
    U val2;
};

I wasn't sure what to draw from the recommendation warning, other than that maybe I have to put somewhere in the friend declaration. Does anyone know the proper syntax for this? Thanks.

Paisano answered 19/8, 2009 at 2:48 Comment(0)
A
21

You declare operator<< as returning an ostream&, but there is no return statement at all in the method. Should be:

template <class T, class U>
ostream& operator<<(ostream& out, Pair<T,U>& v)
{
    return out << v.val1 << " " << v.val2;
}

Other than that, I have no problems or warnings compiling your code under Visual Studio 2008 with warnings at level 4. Oh, there are the classical linker errors, but that is easily bypassed by moving the template function definition to the class declaration, as explained in the C++ FAQ.

My test code:

#include <iostream>
using namespace std;

template <class T, class U>
class Pair{ 
public:
    Pair(T v1, U v2) : val1(v1), val2(v2){}
    ~Pair(){}
    Pair& operator=(const Pair&);
    friend ostream& operator<<(ostream& out, Pair<T,U>& v)
    {
        return out << v.val1 << " " << v.val2;
    }
private:    
    T val1;
    U val2;
};

int main() {
    Pair<int, int> a(3, 4);
    cout << a;      
}
Agitate answered 19/8, 2009 at 3:1 Comment(0)
F
46

You want to make one single instance (called "specialization" in generic terms) of that template a friend. You do it the following way

template <class T, class U>
class Pair{
public:
    Pair(T v1, U v2) : val1(v1), val2(v2){}
    ~Pair(){}
    Pair& operator=(const Pair&);
    friend ostream& operator<< <> (ostream&, Pair<T,U>&);

private:
    T val1;
    U val2;
};

Because the compiler knows from the parameter list that the template arguments are T and U, you don't have to put those between <...>, so they can be left empty. Note that you have to put a declaration of operator<< above the Pair template, like the following:

template <class T, class U> class Pair;

template <class T, class U>
ostream& operator<<(ostream& out, Pair<T,U>& v);

// now the Pair template definition...
Ferdelance answered 19/8, 2009 at 2:52 Comment(3)
+1 This is actually what the compiler is complaining about. The other answer deals with the problem with a workaround: instead of telling the compiler that the friend is the specialization of the template it creates a non-templated operator<< function for the given types.Warnke
I agree with David; this is the best solution in terms of best practice and good programming.Backflow
Wow, the extra <> is easy to miss!Sanitarian
A
21

You declare operator<< as returning an ostream&, but there is no return statement at all in the method. Should be:

template <class T, class U>
ostream& operator<<(ostream& out, Pair<T,U>& v)
{
    return out << v.val1 << " " << v.val2;
}

Other than that, I have no problems or warnings compiling your code under Visual Studio 2008 with warnings at level 4. Oh, there are the classical linker errors, but that is easily bypassed by moving the template function definition to the class declaration, as explained in the C++ FAQ.

My test code:

#include <iostream>
using namespace std;

template <class T, class U>
class Pair{ 
public:
    Pair(T v1, U v2) : val1(v1), val2(v2){}
    ~Pair(){}
    Pair& operator=(const Pair&);
    friend ostream& operator<<(ostream& out, Pair<T,U>& v)
    {
        return out << v.val1 << " " << v.val2;
    }
private:    
    T val1;
    U val2;
};

int main() {
    Pair<int, int> a(3, 4);
    cout << a;      
}
Agitate answered 19/8, 2009 at 3:1 Comment(0)
D
1

Simple inline version:

template<typename T> class HasFriend {
    private:
        T item;
    public:
       ~HasFriend() {}
       HasFriend(const T &i) : item(i) {}
    friend ostream& operator<<(ostream& os, const HasFriend<T>& x) {
        return os << "s(" << sizeof(x) << ").op<<" << x.item << endl;
    }
};

Revised template version:

template<template<typename /**/> class U, typename V>
ostream& operator<<(ostream &os, const U<V> &x) {
    return os << "s(" << sizeof(x) << ").op<<" << x.item << endl;
}

template<typename T> class HasFriend {
    private:
        T item;
    public:
       ~HasFriend() {}
       HasFriend(const T &i) : item(i) {}
    friend ostream& operator<<<>(ostream&, const HasFriend<T>&);
};
Decoct answered 25/8, 2014 at 19:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.