return type of operator+()

Discussion in 'C++' started by subramanian100in@yahoo.com, India, Sep 18, 2009.

  1. , India

    , India Guest

    Consider the following class( For simplicity I have not given the
    member function definitions).

    class Test
    {
    public:
    explicit Test(int arg = -1);
    Test(const Test& arg);
    Test& operator=(const Test& rhs);
    Test& operator+=(const Test& rhs);
    int getValue(void) const;

    private:
    int value;
    };

    Suppose I define the overloaded operator+() as

    inline const Test operator+(const Test& lhs, const Test& rhs)
    {
    Test temp = lhs;
    temp += rhs;
    return temp;
    }

    Consider the three instances of the class Test.
    Test a(100);
    Test b(200);
    Test c(300);

    I have kept the return type of operator+() as 'const Test' instead of
    plain 'Test'. The reason is that if the return type were plain 'Test',
    then it will allow the following expression:
    (a + b) = c;

    But we cannot write
    (x + y) = z;
    if x, y, z were built-in types. So, to mimic built-in types, the
    overloaded operator+() has to return 'const Test' instead of plain
    'Test' so that '(a+b) = c' will be disallowed by the compiler. Am I
    correct ? Kindly advice me what is practiced regarding the return type
    of operator+() in real-world applications?

    Thanks
    V.Subramanian
    , India, Sep 18, 2009
    #1
    1. Advertising

  2. , India

    Scooser Guest

    Hi,
    you cannot write (a + b) = c but also c = (a + b).someNonConstMethod()
    is not possible any longer.

    btw. why creating the temp object yourself? Let the compiler do this
    for you.

    inline const Test operator+ (Test lhs, const Test& rhs)
    {
    return lhs += rhs;
    }
    Scooser, Sep 18, 2009
    #2
    1. Advertising

  3. , India

    SG Guest

    On 18 Sep., 11:13, Scooser wrote:
    > you cannot write (a + b) = c but also c = (a + b).someNonConstMethod()
    > is not possible any longer.


    Right. In C++0x a better approach would be to limit assignment to
    lvalues instead of using const return values. This will make

    (a+b)=c;

    ill-formed but still allow

    (a+b).someNonConstFunction()

    if someNonConstFunction has no lvalue-ref-qualifier. Also, it allows
    moving resources from (non-const) temporary objects to other objects
    (move semantics). For small objects that only contain an integer this
    won't matter. But in other cases like std::valarray it will make a
    difference. An assignment operator restricted to lvalues will look
    like this:

    class Test {
    ...
    public:
    Test& operator=(Test const&) & ;
    // note the ref qualifier: ^^^
    ...
    };

    In the light of C++0x, move constructors and ref qualifiers, the habit
    of returning const objects is probably going to disappear. Even
    without C++0x I don't return const objects. I just don't consider (a+b)
    =c to be a problem.

    > btw. why creating the temp object yourself? Let the compiler do this
    > for you.
    >
    > inline const Test operator+ (Test lhs, const Test& rhs)
    > {
    >    return lhs += rhs;
    > }


    Before recommending something like this, please make sure that it is
    actually an improvement over what the OP wrote. The problem here is
    that no compiler I know of will be able to apply RVO (return value
    optimization) in this case. For two reasons, actually. Firstly: It's a
    parameter. Secondly: the return type of operator+= is an lvalue
    reference. How would the compiler know what this reference refers to
    without inlining the operator+= function? The compilers I tested are
    not able to figure that out even with an inline operator+= and
    optimizations enabled.

    Assuming your compiler can apply URVO and NRVO except for parameters
    (which is the behaviour of both Microsoft's and GNU's C++ compiler as
    far as I know) and further assuming that your compiler can elide a
    copy if the argument was an rvalue we get the following results:

    1st arg | subramanian | Scooser
    --------+-------------+--------
    lvalue | 1 | 2
    rvalue | 1 | 1

    Table 1: Count of copy constructions

    The one copy in subramanian's is the copy he created manually. NRVO
    applies. RVO is not applied in Scooser's version at all. But in case
    of rvalue arguments the copy can be elided which is why it also uses
    only one copy construction. But for lvalue arguments two copy
    constructions are used.

    Cheers,
    SG
    SG, Sep 18, 2009
    #3
  4. , India wrote:
    > Consider the following class( For simplicity I have not given the
    > member function definitions).
    >
    > class Test
    > {
    > public:
    > explicit Test(int arg = -1);
    > Test(const Test& arg);
    > Test& operator=(const Test& rhs);
    > Test& operator+=(const Test& rhs);
    > int getValue(void) const;
    >
    > private:
    > int value;
    > };
    >
    > Suppose I define the overloaded operator+() as
    >
    > inline const Test operator+(const Test& lhs, const Test& rhs)
    > {
    > Test temp = lhs;
    > temp += rhs;
    > return temp;
    > }
    >
    > Consider the three instances of the class Test.
    > Test a(100);
    > Test b(200);
    > Test c(300);
    >
    > I have kept the return type of operator+() as 'const Test' instead of
    > plain 'Test'. The reason is that if the return type were plain 'Test',
    > then it will allow the following expression:
    > (a + b) = c;


    So? What's the big deal?

    > But we cannot write
    > (x + y) = z;
    > if x, y, z were built-in types.


    No. Neither can we call member functions for built-in types.

    > So, to mimic built-in types, the
    > overloaded operator+() has to return 'const Test' instead of plain
    > 'Test' so that '(a+b) = c' will be disallowed by the compiler. Am I
    > correct ?


    Correct in what sense? If you are writing a template function that is
    supposed to use binary operator+, and you expect to use that function
    with both built-in types and some user-defined ones, it would never have
    such a senseless code like (a+b)=c (because if you try, you can't use
    that code with built-in types, as you said). If you're writing code to
    exclusively use your type (and not built-in types), then what does it
    matter whether your type mimics built-in types to a tee? Mimicking is
    never exact, otherwise you'd have a copy. That's why you only implement
    *part* of the functionality, the *important* part. The rest is fluff.

    > Kindly advice me what is practiced regarding the return type
    > of operator+() in real-world applications?


    Just an object. The fact that you can use a non-const member function
    on the result of an expression and have it modify the temporary returned
    before it's used in the rest of the expression is the added bonus that
    does not exist in built-in types.

    Bottom line: don't overthink it.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Sep 18, 2009
    #4
  5. , India

    James Kanze Guest

    On Sep 18, 10:59 am, ", India"
    <> wrote:
    > Consider the following class( For simplicity I have not given
    > the member function definitions).


    > class Test
    > {
    > public:
    > explicit Test(int arg = -1);
    > Test(const Test& arg);
    > Test& operator=(const Test& rhs);
    > Test& operator+=(const Test& rhs);
    > int getValue(void) const;


    > private:
    > int value;
    > };


    > Suppose I define the overloaded operator+() as


    > inline const Test operator+(const Test& lhs, const Test& rhs)
    > {
    > Test temp = lhs;
    > temp += rhs;
    > return temp;
    > }


    > Consider the three instances of the class Test.
    > Test a(100);
    > Test b(200);
    > Test c(300);


    > I have kept the return type of operator+() as 'const Test'
    > instead of plain 'Test'. The reason is that if the return type
    > were plain 'Test', then it will allow the following
    > expression:
    > (a + b) = c;


    > But we cannot write
    > (x + y) = z;
    > if x, y, z were built-in types. So, to mimic built-in types,
    > the overloaded operator+() has to return 'const Test' instead
    > of plain 'Test' so that '(a+b) = c' will be disallowed by the
    > compiler. Am I correct ?


    Yes. Most people don't bother, but it is the preferred
    solution, at least by some authors. (Scott Meyers, IIRC).

    > Kindly advice me what is practiced regarding the return type
    > of operator+() in real-world applications?


    Follow the local coding guidelines:). Seriously, return a
    value, not a reference; whether the value is const or not is
    more a question of style---as you noted, const comes slightly
    closer to emulating the built-in operator, but it's not a
    familiar idiom, which may cause some readers to wonder, and the
    mistakes it protects against aren't that frequent, so it may not
    be worth the bother. (I decided a long time ago that my return
    values from such operators should be const, but I've never
    gotten around to actually modifying my existing code:).)

    --
    James Kanze
    James Kanze, Sep 19, 2009
    #5
  6. , India

    James Kanze Guest

    On Sep 18, 11:13 am, Scooser <> wrote:

    > you cannot write (a + b) = c but also c = (a +
    > b).someNonConstMethod() is not possible any longer.


    Which is, of course, the goal.

    > btw. why creating the temp object yourself? Let the compiler
    > do this for you.


    > inline const Test operator+ (Test lhs, const Test& rhs)
    > {
    > return lhs += rhs;
    > }


    Maybe he likes readable code.

    --
    James Kanze
    James Kanze, Sep 19, 2009
    #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. jaivrat
    Replies:
    4
    Views:
    494
    jaivrat
    Feb 2, 2005
  2. Greenhorn
    Replies:
    15
    Views:
    780
    Keith Thompson
    Mar 6, 2005
  3. Gernot Frisch

    operator with differing return type?

    Gernot Frisch, Jun 29, 2005, in forum: C++
    Replies:
    10
    Views:
    464
    Gernot Frisch
    Jun 30, 2005
  4. Martin T.
    Replies:
    7
    Views:
    805
    Martin T.
    Mar 10, 2008
  5. Qi
    Replies:
    2
    Views:
    667
Loading...

Share This Page