gedamial gedamial - 3 months ago 12
C++ Question

Why does cout << "hello" choose the non-member version of the operator<<?

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:


  • Non-member operator<< overloads are 13

  • Member operator<< overloads (for cout) are 16



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.


  • Why isn't there a member operator<< for the cout object which takes a const char[]?



Also, on the fourth line we get an error because there's no non-member operator<< overload which takes an integer.


  • Why isn't there a non-member operator<< which takes an integer?



And, last but not least


  • Why does
    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*?

Answer

Why isn't there a member operator<< for the cout object which takes a const 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 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*?

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.