::std::ostream << char

Discussion in 'C++' started by Stefan Ram, May 18, 2011.

  1. Stefan Ram

    Stefan Ram Guest

    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.)
     
    Stefan Ram, May 18, 2011
    #1
    1. Advertising

  2. * 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

    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach /Usenet, May 19, 2011
    #2
    1. Advertising

  3. Stefan Ram

    red floyd Guest

    On May 18, 3:54 pm, -berlin.de (Stefan Ram) wrote:
    >   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?
     
    red floyd, May 19, 2011
    #3
  4. Stefan Ram

    Stefan Ram Guest

    red floyd <> writes:
    >On May 18, 3:54 pm, -berlin.de (Stefan Ram) wrote:
    >>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?


    The obvious is that I was referrring to members of
    »::std::eek:stream«, not of double (nor »*DOUBLE*« or »DOUBLE«).
     
    Stefan Ram, May 19, 2011
    #4
  5. Stefan Ram

    Björn Guest

    Alf P. Steinbach /Usenet wrote:

    > * 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.


    In the current draft N3242 from 2011-02-28 it is still as described.

    >> 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.


    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".

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

    >
    > 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
     
    Björn, May 19, 2011
    #5
  6. Stefan Ram

    red floyd Guest

    On May 19, 10:34 am, -berlin.de (Stefan Ram) wrote:
    > red floyd <> writes:
    > >On May 18, 3:54 pm, -berlin.de (Stefan Ram) wrote:
    > >>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?

    >
    >   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.
     
    red floyd, May 19, 2011
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. lovecreatesbeauty
    Replies:
    1
    Views:
    1,070
    Ian Collins
    May 9, 2006
  2. Johannes Barop
    Replies:
    1
    Views:
    439
    JH Trauntvein
    Dec 29, 2005
  3. Replies:
    2
    Views:
    1,917
  4. Pallav singh
    Replies:
    3
    Views:
    4,063
    Saeed Amrollahi
    Oct 21, 2009
  5. , India
    Replies:
    3
    Views:
    2,879
    James Kanze
    Nov 13, 2010
Loading...

Share This Page