为什么我可以在operator + =的右侧使用初始化列表,但不能使用operator +?

时间:2017-03-04 23:01:00

标签: c++ operator-overloading initializer-list

这是对an earlier question about why I can't use a brace-enclosed initializer as an argument to operator+的跟进,通过查看this earlier question on the subject解决了这个问题。

考虑以下C ++代码,您可以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;
}

main中使用operator+和括号括起初始化列表的行不能编译(并且在询问之前的问题后,我现在知道为什么会这样)。但是,我很困惑为什么在opeartor+=中使用main的代码确实编译得很好。

我很困惑为什么我可以重载+=并让它工作正常,而重载+似乎无法在这里工作。标准中是否有一个特定条款允许在+=运算符而不是+运算符的上下文中使用括号括起的初始值设定项?或者这只是一个奇怪的编译怪癖?

3 个答案:

答案 0 :(得分:22)

this question的答案中解释了这一点(与您链接的问题相关联)。

语言语法只允许某些语法上下文中的支撑列表,而不是任意表达式。该列表包括赋值运算符的右侧,但不包括运算符的右侧。

+=是一个赋值运算符,+不是。

赋值表达式的语法是:

  

  assignment-expression:
     conditional-expression
     logical-or-expression assignment-operator initializer-clause
     throw-expression
  assignment-operator: one of
      = *= *= /= %= += -= >>= <<= &= ^= |=
  

答案 1 :(得分:10)

C ++14§5.17/ 9:

  

braced-init-list 可能会出现在

的右侧      
      
  • 对标量的赋值,在这种情况下,初始化列表最多只能包含一个元素。 x={v}的含义T是表达式x的标量类型,是x=T{v}的含义。 x={}的含义是x=T{}
  •   
  • 对类类型对象的赋值,在这种情况下,初始化列表作为参数传递给由重载决策(13.5.3,13.3)选择的赋值运算符函数。
  •   

这适用于 a += b ,其价格为$ 5.7 / 7等于 a = + b (除了 a 仅对+=评估一次)。换句话说,由于M.M.的评论,因为内置运算符+=的等价性被视为赋值运算符,而不是特殊的更新运算符。 因此,上面引用的关于“赋值”的文字适用于+=

答案 2 :(得分:7)

+=运算符是复合赋值。该标准明确允许在赋值右侧的初始化列表:

  

§8.5.4/ 1 [...]注意:可以使用列表初始化

     

...

     

- 在作业的右侧(5.17)

§5.17谈论所有作业,包括复合作业:

  

赋值表达式:
    - 条件表达式
    - logical-or-expression assignment-operator initializer-clause
    - throw-expression

     

赋值操作符:中的一个   = *= /= %= += -= >>= <<= &= ˆ= |=