Mikhail R. Mikhail R. - 3 months ago 15
C++ Question

How to properly overload the insertion operator for a templated class that's part of a user-defined namespace?

I checked the answers to this question: Overloading operator<< for a templated class, but unfortunately nothing is working for me so far. Meaning, the compiler is constantly throwing myriad errors at me.

#include <iostream>


namespace usr {
// Forward declarations
template <typename T> class A;
template <typename T>
std::ostream& operator<<(std::ostream& os, const usr::A<T>&);

template <typename T>
class A {
public:
friend std::ostream& operator<<(std::ostream& os,
const usr::A<T>& a);
};

template <typename T>
std::ostream& operator<<(std::ostream& os, const usr::A<T>& a) {
os << "test";
return os;
}
}

int main() {
usr::A<int> a;
std::cout << a << std::endl;


return 0;
}


The error I get:

$ g++ -std=c++11 test.cpp && ./a.out
test.cpp:15:67: warning: friend declaration ‘std::ostream& usr::operator<<(std::ostream&, const usr::A<T>&)’ declares a non-template function [-Wnon-template-friend]
const usr::A<T>& a);
^
test.cpp:15:67: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
/tmp/ccklebu2.o: In function `main':
test.cpp:(.text+0x24): undefined reference to `usr::operator<<(std::ostream&, usr::A<int> const&)'
collect2: error: ld returned 1 exit status


The following version doesn't not work either:

#include <iostream>

namespace usr {
template <typename T>
class A {
public:
friend std::ostream& operator<<(std::ostream& os, const usr::A& a) {
os << "test";
return os;
}
};
}

int main() {
usr::A<int> a;
std::cout << a << std::endl;


return 0;
}


Here's the error I get plus a whole lot more which I'm not going to include here:

test2.cpp:8:55: error: invalid use of template-name ‘usr::A’ without an argument list
const usr::A& a) {

Answer

You need to take ostream in your function by reference. Also, when you declare a friend you need to include the template argument: friend std::ostream& operator<< <T>. Here's your first version modified that works for me:

#include <iostream>

namespace usr {
    // Forward declarations
    template <typename T> class A;

    template <typename T>
    std::ostream& operator<<(std::ostream& os, const usr::A<T>&);

    // Class
    template <typename T>
    class A {
        public:
            friend std::ostream& operator<< <T>(std::ostream& os, const usr::A<T>& a);
    };

    // Friend function
    template <typename T>
    std::ostream& operator<<(std::ostream& os, const usr::A<T>& a) {
        os << "test";
        return os;
    }
}

int main() {
    usr::A<int> a;
    std::cout << a << std::endl;


    return 0;
}
Comments