Reputation: 2355
After looking at the ostream::operator <<
c++ reference,
I noticed the following declarations:
ostream& operator<< (bool val);
ostream& operator<< (short val);
ostream& operator<< (unsigned short val);
ostream& operator<< (int val);
ostream& operator<< (unsigned int val);
ostream& operator<< (long val);
ostream& operator<< (unsigned long val);
ostream& operator<< (float val);
ostream& operator<< (double val);
ostream& operator<< (long double val);
ostream& operator<< (void* val);
ostream& operator<< (streambuf* sb );
ostream& operator<< (ostream& (*pf)(ostream&));
ostream& operator<< (ios& (*pf)(ios&));
ostream& operator<< (ios_base& (*pf)(ios_base&));
But then I found out that there are also the following declarations:
ostream& operator<< (ostream& os, char c);
ostream& operator<< (ostream& os, signed char c);
ostream& operator<< (ostream& os, unsigned char c);
ostream& operator<< (ostream& os, const char* s);
ostream& operator<< (ostream& os, const signed char* s);
ostream& operator<< (ostream& os, const unsigned char* s);
Why are the char/string output operators not member functions?
Upvotes: 10
Views: 1079
Reputation: 10733
The reason for operator<< taking char is not a member function is that there already are functions defined in ostream which write characters to the stream.
basic_ostream& put(Ch c);
basic_ostream& write(const Ch* p, streamsize n);
Consequently these operators are made non-member functions which internally uses these two functions.
Upvotes: 0
Reputation: 92381
The first group of operators are members of the stream class.
Most operator overloads, like those in the second group, are not.
As to the why, it is likely just a historical accident. The operators for built in types can be added to the stream classes, and obviously they were (long before C++ was standardized). The standard just documents existing practice here.
Operators for user defined types obviously cannot be added to the stream classes, so they are implemented as free functions.
In retrospect it would have been more consistent to make all the operators free functions, but that would possibly break some old programs.
Upvotes: 6
Reputation: 14591
The others have described the differences, here's my shot at why they are split.
The non-member versions, which take char
variants as parameters are specialized depending on type of the target stream's base character type and handled depending on locale, because standard defines specific behavior (o << '1'
has different behavior than oo << 33
, it has to be handled properly if o
is basic_ostream<wchar_t>
, etc).
E.g. char
writen to basic_ostream<wchar_t>
is widened, while if written to basic_ostream<char>
it is not (27.6.2.5.4). So actually there are multiple overloads of operator<<
, e.g:
basic_ostream<_Elem, _Traits>& operator<<(basic_ostream<_Elem, _Traits>& _Ostr, char _Ch)
basic_ostream<char, _Traits>& <<(basic_ostream<char, _Traits>& _Ostr, char _Ch)
If they were defined as member functions, you wouldn't be able to specialize them like that as you would have to partially specialize the whole class, not just a single member, since standard doesn't allow partial specialization of member functions.
Upvotes: 2
Reputation: 437854
There are actually two families of overloader operator<<
s, as you have found out.
One family is the overloaded member ostream::operator<<
(which gets the ostream
reference implicitly as the this
pointer) and the other family is the overloaded free function operator<<
which gets the ostream
reference explicitly as an argument.
When you want to add streaming capability to a class of your own, you add a free function.
Upvotes: 1
Reputation: 76795
The first series are member functions, which return *this
so operator chaining works.
The second series are freestanding functions (which as you say you can add for any class so you can stream them to a std::ostream
), which have no this
to return and return os
instead to make operator chaining work.
Note that both work the same way at a call site.
Upvotes: -1