Today I'm trying to understand this thing related to the operator<< and its overloads.
Let's take a look at this code:
cout.operator<<("hello"); // +16 overloads -> implicit conversion to void*
cout.operator<<(123); // +16 overloads
operator<<(cout,"hello"); // +13 overloads
operator<<(cout, 123); // ERROR: no overload
cout << "hello"; // +13 overloads ---> non-member version!
cout << 123; // +16 overloads ---> member version!
Thanks to Visual Studio's Intellisense, I could detect for each one how many overloads it can provide.
I came to the conclusion:
And I got these questions:
As you can see from the last two lines, when using cout with a const char[] the non-member overload is selected.
Also, on the fourth line we get an error because there's no non-member operator<< overload which takes an integer.
And, last but not least
cout << “hello” choose the non-member version of the operator<< ?Maybe because there is a particular non-member operator<< overload which is a good candidate for a const char[], rather than the member-operator<< overload which takes a void*?
Why isn't there a member
operator<<for thecoutobject which takes aconst char[]?
Character strings are handled separately. Creating member operators for std::basic_string would require all streams to have a dependancy on std::basic_string functionality, which is not always desirable. All of the member operators are for built-in language types, but std::basic_string is a class instead, so it has non-member operator overloads. One could argue that const char[] (which decays to const char*) is a built-in type, but operator<< streams const char* similarly to std::basic_string, and it doesn't make sense to split those implementations in two different areas of the library. Functionality for handling character strings, whether using arrays or classes, are usually grouped together.
Why isn't there a non-member operator<< which takes an integer?
Because there doesn't need to be one. It already exists as a member operator. You are not supposed to call member operators directly (unless you need to, which your example does not). You are supposed to just use the operator normally (stream << ...) and let overload resolution pick the correct member or non-member operator, based on parameters, scoping, etc. If you think about it, a non-member overload would cause an ambiquity error. Should stream << 123 call stream.operator<<(123) or ::operator<<(stream, 123)? There can be only one choice, or the compile fails.
Why does
cout << “hello”choose the non-member version of theoperator<<? Maybe because there is a particular non-memberoperator<<overload which is a good candidate for aconst char[], rather than the member-operator<<overload which takes avoid*?
That is exactly why. A typed const char[] parameter is a better match for a narrow string literal then an untyped void* pointer. So, if both operators are in scope (and the const char[] overload is only in scope if you use #include <string>), then the compiler will choose the better matching overload.
IIRC the non-memberness of the const char * overloads was due to a technical reason: the committee wanted wide character streams to also provide const char* output, but if you provide both operator<<(const charT*) and operator<<(const char *) as members then the narrow character stream will be ill-formed for having two member functions with the same signature. Having them as nonmembers solves this problem - they will now just fight it out in overload resolution, and if there's an ambiguity, you just add a more specialized overload.
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