Generally it depends on whether the stream insertion operator <<
for the class is a concrete function or a template.
With <<
as a concrete function, the overload is found, and the conversion done (as long as it's not ambiguous):
#include <iostream>
using namespace std;
template< class CharType >
struct String {};
ostream& operator<<( ostream& stream, String<char> const& s )
{
return (stream << "s");
}
struct MyClass
{
operator String<char> () const { return String<char>(); }
};
int main()
{
cout << "String: " << String<char>() << endl;
cout << "MyClass: " << MyClass() << endl;
}
However, with <<
as a function template, the template matching finds no match, and then conversion via a user-defined operator is not attempted:
#include <iostream>
using namespace std;
template< class CharType >
struct String
{
};
template< class CharType >
ostream& operator<<( ostream& stream, String< CharType > const& s )
{
return (stream << "s");
}
struct MyClass
{
operator String<char> () const { return String<char>(); }
};
int main()
{
cout << "String: " << String<char>() << endl;
cout << "MyClass: " << MyClass() << endl; // !Oops, nyet! Not found!
}
And in your case, std::string
is really just a typedef
for std::basic_string<char>
.
Fix: define a <<
operator for your class or, if you want to avoid the header dependency (thinking build time), define a conversion to e.g. char const*
, or, simplest and what I recommend, make that conversion a named one so that it has to be invoked explicitly.
Explicit is good, implicit is bad.