In test you try to output foo.bar
using printer
, which needs an operator<<
to output bar.
Where printer
is defined, there is no output operator for bar,
which is defined after' printer. If you forward declare printer
and define it after the output operators, everything works.
#include <iostream>
#include <ostream>
namespace ns {
struct Bar {
int x;
};
struct Foo {
Bar bar;
};
}; // namespace ns
// Why does this fix things
#if 0
inline std::ostream& operator<<(std::ostream& os, const ns::Bar& bar);
inline std::ostream& operator<<(std::ostream& os, const ns::Foo& foo);
#endif
template <class T>
std::ostream& printer(std::ostream& os, const T& obj);
// I do not own 'ns' but I want to make a generic printer for it
// Wrapping this in 'namespace ns {...}' is the solution, but why?
inline std::ostream& operator<<(std::ostream& os, const ns::Bar& bar) {
return printer(os, bar);
}
inline std::ostream& operator<<(std::ostream& os, const ns::Foo& foo) {
return printer(os, foo.bar);
}
template <class T>
std::ostream& printer(std::ostream& os, const T& obj) {
os << obj; // error: no match for 'operator<<'
return os;
}
void test() {
ns::Foo foo;
std::cout << foo;
}