29

This is a follow-up to an earlier question about why I can't use a brace-enclosed initializer as an argument to operator+, which was resolved by looking at this earlier question on the subject.

Consider the following C++ code, which you can try live at ideone.com:

#include <iostream>
#include <initializer_list>
using namespace std;

struct AddInitializerList {
    void operator+= (initializer_list<int> values) {
        // Do nothing   
    }
    
    void operator+ (initializer_list<int> values) {
        // Do nothing
    }
};

int main() {
    AddInitializerList adder;
    adder += {1, 2, 3};  // Totally legit
    adder +  {1, 2, 3};  // Not okay!
    
    return 0;
}

The line in main that uses operator+ with a brace-enclosed initializer list does not compile (and, after asking that earlier question, I now know why this is). However, I'm confused why the code that uses operator+= in main does indeed compile just fine.

I'm confused as to precisely why I can overload += and have it work just fine, while overloading + doesn't seem to work here. Is there a particular provision in the standard that permits brace-enclosed initializers in the context of the += operator but not the + operator? Or is this just a weird compiler quirk?

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065

3 Answers3

27

It is explained in the answer to this question (which is linked from the question you linked to).

The language grammar only allows a braced list in certain grammatical contexts, not in place of an arbitrary expression. That list includes the right-hand side of assignment operators, but NOT the right-hand side of operators in general.

+= is an assignment operator, + is not.

The grammar for assignment expressions is:

  assignment-expression:
     conditional-expression
     logical-or-expression assignment-operator initializer-clause
     throw-expression
  assignment-operator: one of
      = *= *= /= %= += -= >>= <<= &= ^= |=
  
Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • @NeilButterworth That is covered in the Q/A I linked to – M.M Mar 04 '17 at 23:21
  • Well, that would definitely explain things. Thanks! – templatetypedef Mar 04 '17 at 23:38
  • 1
    I don't think this is an answer. The question is why the grammar allows brace init list for `+=` but not for `+`. Listing the particular grammar rule just says the OP is not mistaken about what the grammar allows. – Cheers and hth. - Alf Mar 04 '17 at 23:55
  • 2
    @Cheersandhth.-Alf The OP, verbatim, "Is there a particular provision in the standard that permits brace-enclosed initializers in the context of the += operator but not the + operator?" – M.M Mar 05 '17 at 00:04
  • 1
    @Cheersandhth.-Alf The question you're asking is a really, really good one. I've read some other answers quoting folks who say the decision was primarily based on making the parser easier to implement, so I suspect that's what's going on here (and why I didn't ask that question specifically). – templatetypedef Mar 05 '17 at 00:43
10

C++14 §5.17/9:

A braced-init-list may appear on the right-hand side of

  • an assignment to a scalar, in which case the initializer list shall have at most a single element. The meaning of x={v}, where T is the scalar type of the expression x, is that of x=T{v}. The meaning of x={} is x=T{}.
  • an assignment to an object of class type, in which case the initializer list is passed as the argument to the assignment operator function selected by overload resolution (13.5.3, 13.3).

This applies to a+=b via its $5.7/7 equivalence to a=a+b (except that a is evaluated only once for +=). Put another way, due to a comment by M.M., because of the equivalence for the built-in operators += is regarded as an assignment operator, and not a special update operator. Hence the quoted text above about “assignment” applies to +=.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • 2
    It is because `a += b` matches the grammar for assignment expressions, not because of equivalence to `a = a + b` (which is not even true in the case of overloaded operators). The 5.17/7 only refers to the non-overloaded case; see point 3 at the start of clause 5 – M.M Mar 04 '17 at 23:20
  • @M.M. You're right, and that's a trivial observation. You could make it more interesting by claiming that the standard has a defect in section $5, where it fails to to cover user defined `+=`. – Cheers and hth. - Alf Mar 04 '17 at 23:21
7

+= operator is a compound assignment. The standard explicitly permits initializer lists on the right-hand side of assignments:

§8.5.4/1 [...] Note: List-initialization can be used

...

— on the right-hand side of an assignment (5.17)

§5.17 talks about all assignments, including compound ones:

assignment-expression:
- conditional-expression
- logical-or-expression assignment-operator initializer-clause
- throw-expression

assignment-operator: one of
= *= /= %= += -= >>= <<= &= ˆ= |=

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523