operator<< overload for a member type in a template class in C++

142 Views Asked by At

In the code below, I have a template class with a member type(struct Element). I want to overload operator<< for that member type. However, the code won't compile.

I would appreciate it if someone could point out where I am going wrong?

include <iostream>
using namespace std;

// fwd decl
template<class T> class CC;

// operator<< overload template for member type CC<T>::Element
template<class T>
ostream& operator<<(ostream& os, const typename CC<T>::Element& elm) {
    return os << elm.val1 << "/" << elm.val2;
}

template<class T>
class CC
{
public:
    struct Element {    // type member
        int val1;
        int val2;
    };

    template<typename U>
    friend ostream& operator<<(ostream& os, const typename CC<U>::Element& elm);
};

int main() {
    CC<int>::Element elm{0,0};
    cout << elm << endl;     // does not compile due to this!
}
2

There are 2 best solutions below

2
On BEST ANSWER

Template arguments can't be deduced from a nested entity (the short explanation: the type may be seame for different template instantiations). That is, the declaration

template<typename U>
ostream& operator<<(ostream& os, const typename CC<U>::Element& elm);

whether for a friend or not is never considered because the type U can't be deduced. You can fix the problem by making the friend operator a non-template:

// ...
friend ostream& operator<<(ostream& os, const Element& elm) { ... }
// or
friend ostream& operator<<(ostream& os, const CC<T>::Element& elm) { ... }
// ...

The function will need to be implemented in its declaration, though.

2
On

Your problem is that in following code

 ostream& operator<<(ostream& os, const typename CC<T>::Element& elm) {

Element is in non-deduced context. As a result, template argument can not be deduced. And since a call to operator<< with explicit template argument would be really ugly (if possible at all), I suggest to change the overall coding pattern.

For example, you can make elm to be deduced template argument, like

template<typename E>
friend ostream& operator<<(ostream& os, const E& elm);

And than extract actual U from E using specialized struct.