Domanda

This is related to the difference-between-cout-x-and-cout-operator-x question, but still a little different...

#include <iostream>

int main(){
    std::cout << "hello" << std::endl;

    std::cout.operator<<("hello2");
    std::cout.operator<<(std::endl);

    operator<<(std::cout, "hello3");
//    operator<<(std::cout, std::endl);

    return 0;
}

Q1: Why does std::cout.operator<<("hello2"); work?

From other answers on SO I would expect the compiler to complain since operator<< is meant to be a free function and not a member of cout. On my system, however, it prints "0x10d54df31". And, stranger yet, the following line correctly correctly executes std::endl.

Q2: Why does operator<<(std::cout, std::endl); not work?

I know that std::endl is a function, but it seems strange (to me) that the hello3 output works whilst the `std::endl' doesn't. Instead the compiler throws an error:

main.cpp:10:4: error: no matching function for call to 'operator<<'
    operator<<(std::cout, std::endl);

Q3: How can the first std::cout << "hello1" << std::endl; be written in operator<<(...) form?

If the first two questions have been answered, then this has probably already covered. It's the point of this learning exercise, so seems sensible to ask it explicitly.

È stato utile?

Soluzione

Operators can be implemented in different ways, in particular an operator<< for which the left hand side is your type can be implemented as either a free function or as a member function of that left hand side type.

While you must implement ostream& operator<<(ostream&, MyType const&) as a free function (since MyType is not the left hand side), the library implementation can choose* to implement operator<< for some fundamental types insde the std::ostream type (which is really a particular instantiation of a template, I am trying to ignore the details).

Edit: After checking with the standard this is incorrect:

This is what you are noticing in the code, the overload that takes a const char* is implemented as a member of ostream (basic_ostream<char,char_traits<char>).

The overloads taking manipulators are implemented as member functions (Q2), and there is an implicit conversion from const char* to const void* that will be picked if you use the syntax for explicitly calling a member operator (Q1). For Q3, the answer would be:

operator<<(std::cout, "Hello").operator<<(std::endl);

* The implementation is actually not free to choose, since the standard mandates the signatures.

Altri suggerimenti

Some overloads of operator<< are class members, others are not.

In C++03 this created some baffling call scenarios since a reference to non-const (argument of the not-member) can't be bound to an rvalue, but in C++11 at least one such has been fixed by introducing an rvalue reference argument overload.

So, which calls compile or not depends more in general also on the C++ standards version, C++03 or C++11.

There is a bunch of member output operators defined in std::ostream. In retrospect that was probably an error but when IOStreams were first created I think it was actually necessary. These member operators include the overloads taking function pointers which means you'll need to use member notation for those. The operators using C-strings are non-member overloads, i.e., you need to use the non-member function call notation to get the C-string overload. When you call the member operator with a char const* the char const* will be converted to void const* for which there is a member output operator.

Your questions can be broken down to member functions an non-member functions.

Having 13.5.2 Binary operators

A binary operator shall be implemented either by a non-static member function (9.3) with one parameter or by a non-member function with two parameters. Thus, for any binary operator @, x@y can be interpreted as either x.operator@(y) or operator@(x,y). If both forms of the operator function have been declared, the rules in 13.3.1.2 determine which, if any, interpretation is used.

Omitting a quote of 13.3.1.2 the member function (operator) is preferred.

The line 'std::cout << "hello" << std::endl;' involves non member functions. Each 'std::cout.operator' is an explicit member function call.

  • Q1 is the member operator<<(const void*)
  • Q2 there is no member taking a function
  • Q3 It is not possible
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top