I have a template class that defines some member types. It's similar to how std::map
defines it's value_type
based on it's own template arguments, but in my case the type is more complex, so it's defined as nested class.
Now for debugging I would like to define operator<<
for that type. But the compiler tells me it can't deduce the template parameters of the outer template.
My real code is not contrived like the following example, but this contrived example demonstrates the approach I tried and how it fails:
#include <iostream>
template <typename Value> class Outer;
template <typename Value>
std::ostream &operator<<(std::ostream &, const typename Outer<Value>::Inner &);
template <typename Value>
class Outer {
public:
struct Inner {
Value x;
};
void PrintSomething(Value v) {
// the real program does something useful with the inner class, of course
Inner inner = { v };
std::cout << "Inner = " << inner << std::endl; // <---- THIS SAYS IT CAN'T FIND operator<<
};
};
template <typename Value>
std::ostream &operator<<(std::ostream &s, const typename Outer<Value>::Inner &v) {
return s << v.x;
}
int main() {
Outer<int> o;
o.PrintSomething(42);
return 0;
}
This is complete sample to reproduce the problem. The compiler (I've tried 3 of them) says there is no overload of operator<<
that would take second argument of type Outer<int>::Inner
. When I try the same thing with different function that does not have other overloads, it instead says C2783: could not deduce template argument for 'identifier'
, gcc and clang keep saying there is no overload that takes second argument Outer<int>::Inner
).
So is there a way to define operator<<
taking Outer<Value>::Inner
for any Value
as it's right (so it can't be defined as member) argument?
Note: I need it to compile in several compilers and some of them don't have any C++11 features, so I need it to be C++03.
What you have there is a so-called non-deducible context. How could Value
ever be deduced? You can partially specialize class templates, making it practically impossible for the compiler to even try and test every possible instantiation (of which there are.. well, infinite).
There are two workarounds: Take Inner
out of Outer
, or make operator<<
an inline friend. The latter is the usual way people go.
template<class T>
struct Outer{
struct Inner{
T value;
friend std::ostream& operator<<(std::ostream& os, Inner const& v){
return os << v.value:
}
};
// ...
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With