Suppose we had an istream subclass with the following method:
SomeStream& operator>>(Something& something) {
// .. write data into something
}
And we also had the following global method:
Something& operator>>(istream& stream, Something& something) {
// .. write data from stream into something
}
How does C++ know which method to call for the following code:
instanceOfSomeStream >> instanceOfSomething;
Follow up question: what is the better or more common way to allow a SomeStream to be written into a Something - should I add another overload for operator>> in SomeStream, that takes a Something& argument? Or should I go the opposite way, and create an overload in Something that takes a SomeStream? (Actually not in Something, but as a global function because of obvious reasons).
C++ has complicated overload resolution rules in general. In this case it's useful to know that a member function, for the purposes of overload resolution, behaves like a non-member function that takes a reference to the class as an implied first argument, i.e., the choice is between something like [1]
SomeStream& operator>>(SomeStream& somestream, Something& something)
and
Something& operator>>(istream& stream, Something& something)
Of course the return type doesn't matter, and for
instanceOfSomeStream >> instanceOfSomething
the first overload will be chosen because SomeStream is more derived than istream.
Your follow-up question should be a separate question. There's some discussion here which might be related: Should operator<< be implemented as a friend or as a member function?
[1] Note: I say "something like" because this is not exactly correct. For example such a member function can be called on an rvalue object expression even though an lvalue reference is shown above.
Related
To test and display the result of some functions of my library, I am creating a set of handy functions.
I have an execute function that looks like :
template <typename R, typename I>
std::string execute( const std::string& func_name, R(*func_ptr)( const I& ), const I& func_input );
It calls the function, and display the results and arguments in a formatted string that I can send to std::cout.
The problem is that some of my functions do not return convertible-to-string results. I thought I could simply overload the global ::operator std::string with something like:
template <typename T>
operator std::string( const std::vector<T>& v );
But GCC complains:
error: 'operator std::string(const std::vector<T, std::allocator<_CharT> >&)' must be a nonstatic member function
Well, the problem of course is that I cannot add member operators to std::vector, and even for my classes, I don't want to pollute them with "for testing" conversion operators.
I guess that I can add a layer of indirection and use a function instead of a conversion operator, but that would not be the more aesthetic solution. I could also overload ::operator << for std::ostream and use a std::ostringstream, but that also is not the cleanest solution.
I wondered if the global conversion operator is really not overloadable, and if so, why.
Conversion operators (cast operators) must be a member of the convertible class that produces the converted type. As assignment operators, they must be member functions, as your compiler is telling you.
Depending on how much effort you want to put into the debug part of it, you could try to use metaprogramming to forward your execute method to different actual implementations, providing specific ones for containers that will print the contents.
Why don´t you want to provide operator<< for your types? I think that is actually the idiomatic solution. Unlike other languages that you use methods that convert to string to produce printable results, in C++ the idiomatic way is providing operator<< and then using stringstreams (or boost::lexical_cast or some similar solution) to convert to strings based on the operator<< implementation. There is a simple utility class here to create a string from elements that override operator<< if you want to use that for a start point.
I wondered if the global conversion operator is really not overloadable, and if so, why.
No, there is no such thing. Conversion functions must be a member of a class. If it weren't so, it would make overload resolution a particularly vexing problem for the compiler by introducing ambiguities.
There is no user defined global conversion operator. You must control either the target type (in which case a non explicit one parameter constructor is the conversion operator) or the source type (in which case you have to overload the member operator target()).
A conversion function must be a member function. The function may not specify a return type, and the parameter list must be empty. They should be used sparingly and there should be a clear conversion path from one type to another type. Otherwise they can lead to unexpected results and mysterious errors.
Unfortunately there is no such thing as a global casting operator. Surprisingly. But templates are your friend.
Sometimes you do not want to expose the casting to the interface put would want to keep this anonymous for a specific implementation only. I usually add a template as() method to the class which can also do type checks in the cast, etc. and lets you handle the way you want to implement the casting (e.g. dynamic, shared, ref, etc).
Something like this:
template< class EvtT >const EvtT& as() const throw( std::exception )
{
const EvtT* userData = static_cast<const EvtT*>( m_UserData );
ASSERT( userData, "Fatal error! No platform specific user data in input event!" );
return *userData;
}
m_UserData is an anonymous type which only the implementation knows. While this is strictly a non-typed cast (I do not use type cecks here) this could be replaced by a dynamic_cast and proper casting exceptions.
The implementation simply does this:
unsigned char GetRawKey( const InputEvent& ie )
{
const UserEvent& ue = ie.as<const UserEvent>();
...
I try to overload operator<< for my class so that it print member when I do
std::cout << obj;
I see that the way to do this is
std::ostream& operator<<(std::ostream& os, const T& obj)
{
// write obj to stream
return os;
}
What are the basic rules and idioms for operator overloading?
However, I try to make my code conforms to Google C++ style guide
https://google.github.io/styleguide/cppguide.html#Reference_Arguments
It says that passing the reference without const is not allowed except for the case that it is needed by convention such as swap(). Is this overloading operator<< in the same category as swap()? or there is a way to do something like
std::ostream& operator<<(std::ostream* os, const T& obj)
^
? or something that does not take non-const reference as the input.
If so, please teach me how to do that. Thank you.
It says that passing the reference without const is not allowed except for the case that it is needed by convention
Well, the stream is conventionally passed as a non-const reference into the stream insertion and extraction operators, so it would appear that the rule has allowed an exception for you. As such, defining the suggested overload should be conforming to the rule despite accepting a non-const reference argument.
That said, I'm not an authority on what Google would consider as convention. If you work for Google, you should know whom to ask; If you don't then you don't need to get stressed over their style.
When we overload the stream insertion operator to work on user defined objects, we usually define it as a global friend function as follows:
ostream& operator << (ostream& out, const MyClass& x) {
// Do something
return out;
}
My question is, I believe the object cout (which is a global object) is passed as the first argument to this function. But, why? It's a global function, so it is accessible in this function anyway, why pass it as an argument. In other words, why not do the following:
ostream& operator << (const MyClass& x) {
// Do something
return cout;
}
There are two reasons.
One is semantic: the first argument need not be std::cout. It can be any std::ostream, be it std::cerr, a std::ofstream, a std::ostringstream, etc.
The second is syntactic: << necessarily takes two arguments, and there's no way to write an overload without two arguments (though the first argument can be a this argument).
The following code is giving me a compilation error. Can anyone please tell me why?
class mytype {
public:
int value;
mytype(int a) {
value = a;
}
friend ostream& operator<<(ostream& stream, const mytype& a) {
stream << a.value;//works
return stream;
}
friend ostringstream& operator<<(ostringstream& stream, const mytype& a) {
stream << (a.value);//compilation error
return stream;
}
};
Error:
error C2027: use of undefined type
'std::basic_ostringstream<_Elem,_Traits,_Alloc>'
Upon fixing that:
error C2666: 'operator <<' : 18 overloads have similar conversions
Final fix:
Declare constructor as explicit. Works on MSVC then.
I wonder why.
error C2027: use of undefined type 'std::basic_ostringstream<_Elem,_Traits,_Alloc>'
You need #include <sstream> to get the [i/o]stringstream classes.
About the other errors
The problem with an overload of the form
ostringstream& operator<<(ostringstream& stream, const mytype& a)
is that it matches an ostringstream exactly. Why is it a bad thing to have a more exact overload? From the standard, §13.3.3/1-2:
a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2) …
If there is exactly one viable function that is a better function than all other viable functions, then it is the
one selected by overload resolution; otherwise the call is ill-formed
Therefore if operator<<( ostream &, int ) and operator<<( ostringstream &, mytype const & ) are both candidates for stream << value, the former matches int exactly with no conversion but the latter matches ostringstream exactly. Therefore neither can be "not worse" for all arguments, and neither candidate may be chosen.
But the code is valid because of a loophole. Your overload is not a candidate at all, except when you actually use your type in the function call. When you declare/define a friend inside a class block, it does not introduce it to any namespace scope; it merely associates it with the class scope, which allows it to be found if that class type describes one of the arguments being passed.
The standard has this to say about friend declarations, although it's in another section (14.6.5):
Friend declarations do not introduce new names into any scope…
So, MSVC tried to be nice and proactively introduced your friend to its enclosing namespace. Strike against MSVC.
However, when I attempted to add a declaration equivalent to what MSVC did "for free," Comeau and GCC nicely resolved the resulting overloading conflict — strike against them. Or is it? As it turns out, the overloaded call occurs earlier in the file than my recommended declaration. If I move the declaration before class mytype { (which requires forward-declaring mytype), then both properly complain about the ambiguity.
Using an overload before it is declared in namespace scope appears to be well and good according to §3.3-3.4 of the Standard. So actually GCC and Comeau were both in the right. The point of declaration is right after the name of the declared object. (And last I checked, self-referential function declarations can still crash GCC.) ADL invokes unqualified lookup into the enclosing namespace at a point immediately before the enclosing class. (3.4.1/8 final bullet, 3.4.1/9, 3.4.2/2a.) If the friend hasn't been declared before the class, it's legitimately not a candidate. (7.3.1.2/3) Isn't C++ a beautiful language?
How keep the simplified example on GCC, but break subsequent code.
friend ostringstream& operator<<(ostringstream& stream, const mytype& a) {
stream << (a.value);//compilation error
return stream;
}
};
ostringstream& operator<<(ostringstream& stream, const mytype& a); // <- here
Following this declaration, it will be impossible to write an int into an ostringstream.
How to break everything uniformly, with simpler declaration semantics.
class mytype; // <- here
// and here:
inline ostringstream& operator<<(ostringstream& stream, const mytype& a);
class mytype {
public:
Following this declaration, it will be impossible to write an int into an ostringstream… including the friend declarations inside class mytype {}.
Actual solution.
The stream classes are supposed to be indistinguishable. If you really want to determine whether a given stream feeds a string in memory (and you shouldn't), it's best to look at its internal streambuf object, returned by rdbuf(), which actually performs the I/O gruntwork. Even a generic ostream object can have ostringstream functionality if given a stringbuf.
if ( typeid( stream.rdbuf() ) == typeid( stringbuf * ) ) {
// this is effectively a stringstream
} else {
// not a stringstream
}
There is an overload ambiguity in the call to operator<< in the ostringstream overload.
stream << a.value;
There are a number of operator<< overloads that are members of the ostream class, which is a base class of ostringstream. One of these is declared as:
ostream& ostream::operator<<(int);
This overload is an exact match for the right-hand side (a.value is an int) but requires a derived-to-base conversion on the left-hand side (stream is an ostringstream, which is derived from ostream).
However, there is also your ostringstream overload:
ostringstream& operator<<(ostringstream&, const mytype&);
This overload is an exact match for the left-hand side (stream is an ostringstream), and a user-defined converting constructor (your mytype(int) constructor) can be used to convert a.value (an int) to a mytype.
Since one overload matches the first argument better and the other overload matches the second argument better, there is an ambiguity. You can fix this either by:
Explicitly converting the left-hand side to an ostream (using (ostream&)stream = a.value;), or
Remove the user-defined conversion by making the constructor explicit.
To test and display the result of some functions of my library, I am creating a set of handy functions.
I have an execute function that looks like :
template <typename R, typename I>
std::string execute( const std::string& func_name, R(*func_ptr)( const I& ), const I& func_input );
It calls the function, and display the results and arguments in a formatted string that I can send to std::cout.
The problem is that some of my functions do not return convertible-to-string results. I thought I could simply overload the global ::operator std::string with something like:
template <typename T>
operator std::string( const std::vector<T>& v );
But GCC complains:
error: 'operator std::string(const std::vector<T, std::allocator<_CharT> >&)' must be a nonstatic member function
Well, the problem of course is that I cannot add member operators to std::vector, and even for my classes, I don't want to pollute them with "for testing" conversion operators.
I guess that I can add a layer of indirection and use a function instead of a conversion operator, but that would not be the more aesthetic solution. I could also overload ::operator << for std::ostream and use a std::ostringstream, but that also is not the cleanest solution.
I wondered if the global conversion operator is really not overloadable, and if so, why.
Conversion operators (cast operators) must be a member of the convertible class that produces the converted type. As assignment operators, they must be member functions, as your compiler is telling you.
Depending on how much effort you want to put into the debug part of it, you could try to use metaprogramming to forward your execute method to different actual implementations, providing specific ones for containers that will print the contents.
Why don´t you want to provide operator<< for your types? I think that is actually the idiomatic solution. Unlike other languages that you use methods that convert to string to produce printable results, in C++ the idiomatic way is providing operator<< and then using stringstreams (or boost::lexical_cast or some similar solution) to convert to strings based on the operator<< implementation. There is a simple utility class here to create a string from elements that override operator<< if you want to use that for a start point.
I wondered if the global conversion operator is really not overloadable, and if so, why.
No, there is no such thing. Conversion functions must be a member of a class. If it weren't so, it would make overload resolution a particularly vexing problem for the compiler by introducing ambiguities.
There is no user defined global conversion operator. You must control either the target type (in which case a non explicit one parameter constructor is the conversion operator) or the source type (in which case you have to overload the member operator target()).
A conversion function must be a member function. The function may not specify a return type, and the parameter list must be empty. They should be used sparingly and there should be a clear conversion path from one type to another type. Otherwise they can lead to unexpected results and mysterious errors.
Unfortunately there is no such thing as a global casting operator. Surprisingly. But templates are your friend.
Sometimes you do not want to expose the casting to the interface put would want to keep this anonymous for a specific implementation only. I usually add a template as() method to the class which can also do type checks in the cast, etc. and lets you handle the way you want to implement the casting (e.g. dynamic, shared, ref, etc).
Something like this:
template< class EvtT >const EvtT& as() const throw( std::exception )
{
const EvtT* userData = static_cast<const EvtT*>( m_UserData );
ASSERT( userData, "Fatal error! No platform specific user data in input event!" );
return *userData;
}
m_UserData is an anonymous type which only the implementation knows. While this is strictly a non-typed cast (I do not use type cecks here) this could be replaced by a dynamic_cast and proper casting exceptions.
The implementation simply does this:
unsigned char GetRawKey( const InputEvent& ie )
{
const UserEvent& ue = ie.as<const UserEvent>();
...