Topic: why is operator+=() allowed to be non-member function also ?


Author: "subramanian100in@yahoo.com, India" <subramanian100in@yahoo.com>
Date: Sat, 22 Dec 2007 09:11:28 CST
Raw View
I am asking this question for learning purpose only. I will not use
operator+=() as non-member.

Consider the following program:

#include <iostream>
#include <cstdlib>

using namespace std;

class Test
{
public:
Test(int arg = 10);
int val;
};

Test::Test(int arg) : val(arg)
{
        cout << "one arg ctor called" << endl;
}

Test operator+=(Test lhs, Test rhs)
{
        cout << "from operator+=" << endl;
        return Test(lhs.val + rhs.val);
}

int main()
{
        Test obj;

        5 += obj;

        return EXIT_SUCCESS;
}

This program compiles fine with both g++ and VC++ 2005 Express Edition
and both produced the following output:

one arg ctor called
one arg ctor called
from operator+=
one arg ctor called

My question:
Why doesn't the standard make the '+=', '-=', etc. be defined only as
non-static member functions similar to the way that an 'operator=,
operator[], operator(), and operator->' must be non-static member
function, so that it will disallow 5 += obj; (It should disallow
because the constant 5 appears on the left hand side and 5 is not an
lvalue)

Stroustrup in his TC++PL 3rd Edition has mentioned in page 264 that
'operator=, operator[], operator(), and operator->' must be non-static
member functions which will ensure that their first operands will be
lvalues. Why is the same reason not applied to operator+=() ?

Is there any advantage for the operators +=, -=, *=, etc be allowed as
non-member functions ?

Kindly clarify

Thanks
V.Subramanian

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: jon@floorboard.com (Jonathan Biggar)
Date: Sun, 23 Dec 2007 02:02:28 GMT
Raw View
subramanian100in@yahoo.com, India wrote:
.
> Test operator+=(Test lhs, Test rhs)
> {
>         cout << "from operator+=" << endl;
>         return Test(lhs.val + rhs.val);
> }
.
> My question:
> Why doesn't the standard make the '+=', '-=', etc. be defined only as
> non-static member functions similar to the way that an 'operator=,
> operator[], operator(), and operator->' must be non-static member
> function, so that it will disallow 5 += obj; (It should disallow
> because the constant 5 appears on the left hand side and 5 is not an
> lvalue)
>
> Stroustrup in his TC++PL 3rd Edition has mentioned in page 264 that
> 'operator=, operator[], operator(), and operator->' must be non-static
> member functions which will ensure that their first operands will be
> lvalues. Why is the same reason not applied to operator+=() ?
>
> Is there any advantage for the operators +=, -=, *=, etc be allowed as
> non-member functions ?

Your operator +=() is defined with funky parameters.  Since Test is
passed by value, your operator +=() can't persistently modify its left
hand argument.

If you define it in a more "normal" way:

Test &operator +=(Test &lhs, const Test &rhs);

It can modify lhs, and the expression:

 5 += obj;

will no longer compile, because you can't bind the implicit conversion
of '5' to a non-const reference.

--
Jon Biggar
Floorboard Software
jon@floorboard.com
jon@biggar.org

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "=?ISO-8859-1?Q?Daniel_Kr=FCgler?=" <daniel.kruegler@googlemail.com>
Date: Sun, 23 Dec 2007 13:20:33 CST
Raw View
On 22 Dez., 16:11, "subramanian10...@yahoo.com, India"
<subramanian10...@yahoo.com> wrote:
> Test operator+=(Test lhs, Test rhs)

Although the language does not prevent this form, where
the first parameter is given by-value (instead of Test&),
this implementation cannot change it's first argument
and thus violates the usual meaning of +=.

> This program compiles fine with both g++ and VC++ 2005 Express Edition
> and both produced the following output:
>
> one arg ctor called
> one arg ctor called
> from operator+=
> one arg ctor called

This outcome is expected.

> My question:
> Why doesn't the standard make the '+=', '-=', etc. be defined only as
> non-static member functions similar to the way that an 'operator=,
> operator[], operator(), and operator->' must be non-static member
> function, so that it will disallow 5 += obj; (It should disallow
> because the constant 5 appears on the left hand side and 5 is not an
> lvalue)

I think there are at least two different angles to look from:

1) It indeed makes *sense* to allow the implementation of +=, ++,
.. as non-member functions. The reason for this is that otherwise
you could never provide these implementations for an enumeration
type.

2) A valid concern is IMO, why the standard allows any form
of a non-member function form of the mutable operators (pre/post
increment and decrement, all assignment operators). I think
the answer in this case is that there exists rare situations where
even these make sense (e.g. a const copy assignment operator),
the most prominent one being a proxy class.

> Stroustrup in his TC++PL 3rd Edition has mentioned in page 264 that
> 'operator=, operator[], operator(), and operator->' must be non-static
> member functions which will ensure that their first operands will be
> lvalues. Why is the same reason not applied to operator+=() ?

The above quoted examples which require a member
function implementation do not make much sense
for user-defined types that do not have member functions
(a complicated way to describe an enumeration type).
An exception of this rule might be operator=, but the
reason for that is operator= is implicitly declared for
user-defined types and it would lead to hard-to-find bugs,
if someone provides a user-defined declaration of operator=
in another translation unit.

> Is there any advantage for the operators +=, -=, *=, etc be allowed as
> non-member functions ?

I think that provision of these operators for enumeration
types is one valid reason.

Greetings from Bremen,

Daniel Kr   gler

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Andrey Tarasevich <andreytarasevich@hotmail.com>
Date: Mon, 7 Jan 2008 04:51:19 CST
Raw View
subramanian100in@yahoo.com, India wrote:
> ...
> Stroustrup in his TC++PL 3rd Edition has mentioned in page 264 that
> 'operator=, operator[], operator(), and operator->' must be non-static
> member functions which will ensure that their first operands will be
> lvalues. Why is the same reason not applied to operator+=() ?
>
> Is there any advantage for the operators +=, -=, *=, etc be allowed as
> non-member functions ?
> ...

I think the way you see this is is a bit backwards, so to say. The proper way to
see it is that for the purpose of uniformity _all_ overloadable operators are
(and should be) allowed to have both member and non-member (standalone) forms,
unless there is a good reason to prohibit it. So, it is not about _allowing_
compound assignment operators to have standalone form, but rather about
_disallowing_ regular assignment to have standalone form.

The rationale for disallowing standalone regular assignment overloads is given
in D&E, if memory serves, and it is quite different from what you mention above.
It is rooted in certain well-known properties of copy-assignment operator. The
important feature of copy-assignment is that for class types the implementation
always provides an implicit overload if you don't overload it explicitly.
Imagine that you didn't overload copy-assignment in some class's definition, but
somewhere in the middle of some translation unit you suddenly declared your own
copy-assignment operator for this class as a standalone function. In accordance
with the C++ lookup rules, the code above that declaration would have to use the
implicit implementation-provided version of the operator, and the code below
that declaration would have to use your explicit user-declared version. The
meaning of the assignment would change depending on the point of declaration of
your standalone copy-assignment operator. This has always been considered as
something very undesirable in the design of the language. And that's why
standalone copy-assignment overloads were prohibited (and all regular assignment
overloads were prohibited with them).

Compound assignments don't suffer from this problem, so there was no reason to
outlaw standalone overloads for compound assignments.

The rationales behind prohibiting standalone overloads for other operators you
mention are different, but they do/did exist, although AFAIK some of them are no
longer considered to be valid (as in case of overloaded '()').

--
Best regards,
Andrey Tarasevich

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "=?ISO-8859-1?Q?Pedro_Lamar=E3o?=" <pedro.lamarao@gmail.com>
Date: Mon, 7 Jan 2008 11:56:35 CST
Raw View
On 23 dez 2007, 00:02, j...@floorboard.com (Jonathan Biggar) wrote:

> Your operator +=() is defined with funky parameters.  Since Test is
> passed by value, your operator +=() can't persistently modify its left
> hand argument.
>
> If you define it in a more "normal" way:
>
> Test &operator +=(Test &lhs, const Test &rhs);
>
> It can modify lhs, and the expression:
>
>         5 += obj;


Hum... Current GCC 4.3 compiles this without complaint:

#include <iostream>
#include <cstdlib>

using namespace std;

class Test
{
public:

  Test(int arg = 10);

  int val;

};

Test::Test(int arg) : val(arg)
{
        cout << "one arg ctor called" << endl;
}

Test operator+=(Test&& lhs, Test const& rhs)
{
        cout << "from operator+=" << endl;
        return Test(lhs.val + rhs.val);
}

int main()
{
        Test obj;

        5 += obj;

        return EXIT_SUCCESS;
}


[psilva@desen gcc]$ /opt/gcc-4.3/bin/g++ --std=c++0x test.cpp
[psilva@desen gcc]$ /opt/gcc-4.3/bin/g++ -Wall --std=c++0x test.cpp -o
test
[psilva@desen gcc]$ ./test
one arg ctor called
one arg ctor called
from operator+=
one arg ctor called


Should this signature:

 Test operator+=(Test&& lhs, Test const& rhs)

be disallowed?

--
 P.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]