Jon McClung Jon McClung - 29 days ago 6
C++ Question

How to properly overload the operator<< for a class with a collection of nested private classes?

I'd like to implement

operator<<
for my templated class so that it can print all the elements it contains to the given
std::ostream&
. The issue is that I can't seem to get it to recognize the function that I've defined.

The error I get is

error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'Outer<int>::Inner')
os << inner << ", ";
~~~^~~~~~~~


Ideally I'd like not to have the function defined inline, but I can't even get it to work inline. In the code below you can see that I've commented out my attempt at defining it outside the class declaration. It produces the same error as above.

This question recommends making the operator a friend of the class. I've done that every way I can think of and it still doesn't work.

The code:

#include <iostream>

template<class T>
class Outer {
class Inner {
T item;
template<class T_>
friend std::ostream& operator<<(std::ostream& os, const typename Outer<T_>::Inner& inner) {
os << inner.item;
return os;
}
template<class T_>
friend std::ostream& operator<<(std::ostream& os, const Outer<T_> outer);
};
std::vector<Inner> inner_items;
template<class T_>
friend std::ostream& operator<<(std::ostream& os, const Outer<T_> outer);
template<class T_>
friend std::ostream& operator<<(std::ostream& os, const typename Outer<T_>::Inner& bar);

};

/*template<class T>
std::ostream& operator<<(std::ostream& os, const typename Outer<T>::Inner& bar) {
os << inner.item;
return os;
}*/

template<class T>
std::ostream& operator<<(std::ostream& os, const Outer<T> outer) {
for (typename Outer<T>::Inner inner : outer.inner_items) {
os << inner << ", ";
}
return os;
}


int main()
{
Outer<int> outer;
std::cout << outer;
}

Answer

You don't need (neither want) to templetize in Inner, just use the type:

class Outer {
    class Inner {
        T item;
        friend std::ostream& operator<<(std::ostream& os, const Inner& inner) {
            os << inner.item;
            return os;
        }
        // ...

What you wrote above fails because you define a free function in Outer<T>::Inner which is operator<<(..). The second parameter is Outer<T_>::Inner and the compiler cannot go from Inner to the type in which it was defined.