14

For educative purposes, I wish to overload and use the += operator in cascade.

class a {
    public:
        a();
        a& operator+= (float f);
    private:
        float aa;
}

a() {
    aa = 0;
}

a& operator+= (float f) {
    aa += f;
    return *this;
}

a b;
b += 1.0; // Works.
b += 1.0 += 1.0; // Error : Expression must be a modifiable lvalue.

I don't understand why the above doesn't work (aside of the possible syntax mistakes -- didn't try to compile this sample code). Returning *this in the overloaded operator+= method, I would expect the second += 1.0 to be called on the b object, no?

Thanks.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
user3020233
  • 327
  • 3
  • 10
  • 1
    You should post code without extra "fun" errors that are unrelated to the problem you are trying to illustrate. – juanchopanza Feb 04 '14 at 17:21
  • Honestly I always did something like b += 1.0 + 2.0; – IssamTP Feb 04 '14 at 17:22
  • [Operator precedence](http://en.cppreference.com/w/cpp/language/operator_precedence). `+=` is evaluated right-to-left. –  Feb 04 '14 at 17:22

3 Answers3

26
b += 1.0 += 1.0;

The associativity for += is right-to-left. So the above is interpreted as:

(b += (1.0 += 1.0));

Does that make sense? NO.

In order to make it work, you need to write it as:

(b += 1.0) += 1.0;

Hope that helps.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
1

Please note that in order to have a class a with the least amount of surprise for its users, it's probably best to also define a member function

a& operator+=(a const&); 

as well as non-member functions

a operator+(a const&, a const&); 
a operator+(a const&, float); 
a operator+(float, a const&);

that are each defined in terms of one of the member operator+= overloads. Then you can write

a1 += b1 + c1; 

where a1 is of type a the variables b1, c1 can both be either float or a. See this question from the for more details.

Community
  • 1
  • 1
TemplateRex
  • 69,038
  • 19
  • 164
  • 304
  • `a operator+(a, a const&); ` is better than `a const&` version, isn't it? – Nawaz Feb 04 '14 at 18:38
  • @Nawaz Sure, but I had hoped to avoid the entire efficiency business and lvalue/rvalue discussion here, since you could also have 2 overloads for `operator+=` and 4 overloads of `operator+` with all the combinations of `a&&` and `a const&`. See e.g. https://github.com/d-frey/operators The point I am making here is that to "do as the ints do" requires at least a few overloads of `a` and `float` as well as an `operator+` to go along the single `operator+=`. – TemplateRex Feb 04 '14 at 18:44
0

Just to add to the fine answers you got. You might be interested in converting constructors and/or conversion operators. For instance:

class a {
    public:
        a();
        a(float f);
        a& operator+= (float f);
        operator float() const;
    private:
        float aa;
};

a::a() {
    aa = 0;
}

a::a(float f) {
    aa = f;
}

a& a::operator+= (float f) {
    aa += f;
    return *this;
}

a::operator float() const {
    return aa;
}

int main()
{
    a b = 1.0;
    b += 1.0; // Works.
    b += (a)1.0 += 1.0; // Works.
}

or maybe better without conversion operator, but with operator+=(const a&);

class a {
    public:
        a();
        a(float f);
        a& operator+= (float f);
        a& operator+= (const a & x);
    private:
        float aa;
};

a::a() {
    aa = 0;
}

a::a(float f) {
    aa = f;
}

a& a::operator+= (float f) {
    aa += f;
    return *this;
}

a& a::operator+= (const a & x) {
    aa += x.aa;
    return *this;
}

int main()
{
    a b = 1.0;
    b += 1.0; // Works.
    b += (a)1.0 += 1.0; // Works.
}
ciamej
  • 6,918
  • 2
  • 29
  • 39