为什么我可以在运算符 += 的右侧使用初始值设定项列表,而不是运算符 +?



这是之前关于为什么我不能使用大括号括起来的初始值设定项作为operator+参数的后续问题,这个问题通过查看之前关于该主题的问题得到解决。

请考虑以下C++代码,您可以在 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+行无法编译(并且在提出前面的问题之后,我现在知道为什么会这样)。但是,我很困惑为什么在main中使用operator+=的代码确实可以很好地编译。

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

这个问题的答案中有解释(从您链接到的问题链接)。

语言语法只允许在某些语法上下文中使用大括号列表,而不是代替任意表达式。 该列表包括赋值运算符的右侧,但不包括一般运算符的右侧。

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

赋值表达式的语法为:

赋值表达式:条件表达式逻辑或表达式赋值运算符初始值

设定项子句出表达式赋值运算符:之一= *= *= /= %= += -= >>= <<= &= ^= |=

C++14 §5.17/9:

">一个带大括号的初始化列表可能会出现在

  • 标量的赋值,在这种情况下,初始值设定项列表最多应具有单个元素。x={v}的意思,其中T是表达式x的标量类型,是x=T{v}的意思。x={}的意思是x=T{}
  • 对类类型的对象的赋值,在这种情况下,初始值设定项列表将作为参数传递给重载解析 (13.5.3、13.3) 选择的赋值运算符函数。

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

+=运算符是一个复合赋值。该标准明确允许在赋值的右侧使用初始值设定项列表:

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

— 在作业的右侧 (5.17)

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

赋值表达式:
- 条件表达式 - 逻辑或表达式赋值运算符初始值设定项子句
- 抛出表达式

赋值运算符:以下之一
=*=/=%=+=-=>>=<<=&=ˆ=|=

最新更新