This question already has answers here:
Closed 7 years ago.
Possible Duplicate:
Overload resolution failure when streaming object via implicit conversion to string
I know it's not such a good idea to do this, but I really want to know the reason why the code below does not compile (i.e. why there is "no acceptable conversion"):
#include <iostream>
#include <string>
class Test
{
public:
operator std::string () const;
};
Test::operator std::string () const
{
return std::string("Test!");
}
int main ()
{
std::string str = "Blah!";
std::cout << str << std::endl;
Test test;
str = test;//implicitly calls operator std::string without complaining
std::cout << str << std::endl;
std::cout << test;//refuses to implicitly cast test to std::string
return 0;
}
On Visual Studio 2010 I get this error: "error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'Test' (or there is no acceptable conversion)
"
Does the <<
operator implicitly cast std::string
to something else in order to make use of it? If yes, what operator do I need to overload in my class to make such a thing work? I refuse to believe that I would actually need to use operator char *
.
operator<<(std::basic_ostream&, std::basic_string)
is a function template and user defined conversions are not considered during template argument deduction. You need to overload operator<<
for your class.
Another option, of course, is a cast
std::cout << static_cast<std::string>(test);
The problem is that std::string
is a specialisation of a template, std::basic_string<char>
, and the required overload of operator<<
is itself a template:
template<class charT, class traits, class Allocator>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&& os,
const basic_string<charT,traits,Allocator>& str);
In order to be used for template argument deduction, a user-defined type has to be an exact match; conversions are not considered.
You will need to either provide an overload of operator<<
for your class, or explicitly convert to std::string
.
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.
I think the operator you need to override is "<<" .
You need to override the operator<<
method.
std::ostream & operator <<(std::ostream & os, const Test & t) {
return os << std::string(t);
}