I'm trying to define a << operator for a set of classes; the set is open, but all of the members have a common tagging base class, and all have the member function std::string String() const
. Basically, what I've got is:
class Tag {};
class Obj : public Tag
{
public:
std::string String() const { return "specialized"; }
};
template <typename T>
typename std::enable_if<std::is_base_of<Tag, T>::type, std::ostream>::value& operator<<( std::ostream& dest, T const& source)
{
dest << source.String();
return dest;
}
int
main()
{
std::cout << typeid(std::enable_if<std::is_base_of<Tag, Obj>::value, std::ostream>::type).name() << std::endl;
std::string s( "generic" );
Obj e;
std::cout << e << std::endl;
std::cout << s << std::endl;
return 0;
}
This doesn't work: with g++ (version 4.8.3, invoked with -std=c++11
), I get the error message:
enableIf.cc: In function 'int main()':
enableIf.cc:55:18: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
std::cout << e << std::endl;
^
In file included from /usr/lib/gcc/x86_64-pc-cygwin/4.8.3/include/c++/iostream:39:0,
from enableIf.cc:8:
/usr/lib/gcc/x86_64-pc-cygwin/4.8.3/include/c++/ostream:602:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = Obj]'
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
I can't figure it out, because there aren't any rvalue-references in sight; the compiler seems to have struck on the generic overload for std::ostream&&
in the standard library.
With MSC (VS 2013), the error message is a lot more verbose, but it starts with:
enableIf.cc(55) : error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'Obj' (or there is no acceptable conversion)
and then goes on to list a lot of possible functions, all in the standard library.
(In my actual code, line 55 corresponds to the line std::cout << e << std::endl;
.)
In both cases, the compiler seems to be rejecting my overloaded function. If I comment out the <<
lines, however, the code compiles, and the value output by the first line in main
seems correct (at least with MSC—the output of g++ is So
, what ever that's supposed to mean).
Given that two compilers agree, I assume that there is an error in my code, but I can't figure out what. How do you do this? (FWIW: I'd be equally happy, or even happier, with a solution which generates the overload for all types having a member function std::string Type::String() const
.)