::std::ostream << char

S

Stefan Ram

The output operator "<<" for operands of type
»::std::eek:stream« and »char« (in this order) seems to be
defined as a non-member, while for »double« it seems to be
defined as a member.

Why is this so?

Bjarne Stroustrup already explained some of this: He said
that "<<" /can/ be defined as a non-member, because the
class already has the member »put«, so it can be defined
outside of the class using »put«. But why do we /prefer/ this?

Herb Sutter explained, why "<<" for his class »Complex« has
to be defined as a non-member of this class »Complex«, but
his reason does not apply to the class »::std::eek:stream« as
far as I understand it.

Sometimes people say: When you define the operators as
non-members and the class has implicit conversion operators,
those implicit conversions will behave more symmetric with
respect to the two operands of a binary operator, when this
operator is defined as a non-member. I can not understand
all of this, because I lack some prerequisites, but I have a
vague idea of what it might mean. Does this reason apply to
»::std::eek:stream« and "<< static_cast<char>(...)"?

Could someone give a specific example of a case where
something would be worse when "<< static_cast<char>(...)"
would have been defined as a member of ::std::eek:stream?

Or, an example of a case where something would be worse when
"<< static_cast<double>(...)" would have been defined as a
non-member of ::std::eek:stream?

(This question is inspired by a similar question posted into
the German language C++ newsgroup by someone else recently.)
 
A

Alf P. Steinbach /Usenet

* Stefan Ram, on 19.05.2011 00:54:
The output operator "<<" for operands of type »::std::eek:stream« and »char« (in
this order) seems to be defined as a non-member, while for »double« it seems
to be defined as a member.

This may depend on which standard you're talking about. I haven't checked but as
I recall some of the issues related to this were fixed in C++0x. Which is on its
way Real Soon Now.

Why is this so?

Historical accident.

Bjarne Stroustrup already explained some of this: He said that "<<" /can/ be
defined as a non-member, because the class already has the member »put«, so
it can be defined outside of the class using »put«. But why do we /prefer/
this?

We don't. Perhaps some do. It depends on what functionality you desire:

* Member (of LHS type), can be called on temporary.

* Non-member (of LHS type), can be invoked on object that just provides
conversion to the relevant formal argument type.

To me, the possibility of calling << with a left hand side operand that just
provides a conversion to referece to the relevant stream type, is completely
irrelevant.


Herb Sutter explained, why "<<" for his class »Complex« has to be defined as
a non-member of this class »Complex«, but his reason does not apply to the
class »::std::eek:stream« as far as I understand it.

Now you're talking about the right hand side operand type.

That's a different thing.

An expression like "a << b" makes sense as "a.operator<<( b )" if the operator
is a member of typeof(a), but not if it is a member of typeof(b).

Sometimes people say: When you define the operators as non-members and the
class has implicit conversion operators, those implicit conversions will
behave more symmetric with respect to the two operands of a binary operator,
when this operator is defined as a non-member. I can not understand all of
this, because I lack some prerequisites, but I have a vague idea of what it
might mean. Does this reason apply to »::std::eek:stream« and "<<
static_cast<char>(...)"?

In practice such conversions do not intrude very much.

However, when you define a symmetric operator like +, then it doesn't make much
sense to single out the left hand argument as special.

So then it might feel much more natural to define a non-member function.

Could someone give a specific example of a case where something would be
worse when "<< static_cast<char>(...)" would have been defined as a member
of ::std::eek:stream?

Define "worse".

Or, an example of a case where something would be worse when "<<
static_cast<double>(...)" would have been defined as a non-member of
::std::eek:stream?

(This question is inspired by a similar question posted into the German
language C++ newsgroup by someone else recently.)

Oh, them Germans.


Cheers & hth.,

- Alf
 
R

red floyd

  The output operator "<<" for operands of type
  »::std::eek:stream« and »char« (in this order) seems to be
  defined as a non-member, while for »double« it seems to be
  defined as a member.

At the risk of asking the obvious... What implementation are you
using where *DOUBLE* is a class type with members?
 
S

Stefan Ram

red floyd said:
At the risk of asking the obvious... What implementation are you
using where *DOUBLE* is a class type with members?

The obvious is that I was referrring to members of
»::std::eek:stream«, not of double (nor »*DOUBLE*« or »DOUBLE«).
 
B

Björn

Alf said:
* Stefan Ram, on 19.05.2011 00:54:

This may depend on which standard you're talking about. I haven't
checked but as I recall some of the issues related to this were
fixed in C++0x. Which is on its way Real Soon Now.

In the current draft N3242 from 2011-02-28 it is still as described.
We don't. Perhaps some do. It depends on what functionality you
desire:

* Member (of LHS type), can be called on temporary.

* Non-member (of LHS type), can be invoked on object that just
provides
conversion to the relevant formal argument type.

To me, the possibility of calling << with a left hand side operand
that just provides a conversion to referece to the relevant stream
type, is completely irrelevant.

I agree. I cannot imagine any reason to define an output stream class
which is not derived from std::basic_ostream but on the other hand
every library and particularly the STL should be as flexible as
possible.

I found at least a reason why some operator<< are members of
std::basic_ostream. They all have operands which will be converted to
several characters usually (numbers, pointers, and another stream
buffer). So, for an implementation it will probably be more efficient
if they insert the produced characters directly into the output buffer
-- if available -- than passing a temporary buffer to
std::basic_ostream::write.

The remaining operator<< in <ostream> only insert single characters.

Another operator<< is in <string> to insert std::basic_string. But in
case of a string you have to copy a character sequence into the output
buffer, anyway, so it doesn't hurt that it's not a member function.

I haven't checked if there are more operator<< in the STL.
However, when you define a symmetric operator like +, then it
doesn't make much sense to single out the left hand argument as
special.

So then it might feel much more natural to define a non-member
function.

For me it feels more natural to define everything inside according to
the rule "as local as possible".
Oh, them Germans.

BTW, I'm the one who came up with the topic. I asked about
std::basic_istream as well but the answer will probably be the same,
so, it's easier to talk only about std::basic_ostream.

Björn
 
R

red floyd

  The obvious is that I was referrring to members of
  »::std::eek:stream«, not of double (nor »*DOUBLE*« or »DOUBLE«).

Sorry, had a brain fart and a parsing error. Duh!!!!

According to the 2003 Standard, it's supposed to be that way.
Arithmetic inserters are members (27.6.2.5.2
[lib.ostream.inserters.arithmetic]), and Character inserters are
function templates (27.6.2.5.4 [lib.ostream.inserters.character]).

Why they did that, who knows.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,699
Latest member
AnneRosen

Latest Threads

Top