Почему я могу использовать списки инициализаций в правой части оператора + =, но не оператор +?
Это следующий вопрос более раннего вопроса о том, почему я не могу использовать инициализатор, заключенный в фигурные скобки, в качестве аргумента operator+
, который был разрешен посмотрев этот более ранний вопрос по этому вопросу.
Рассмотрим следующий код на С++, который вы можете попробовать жить на 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
, действительно компилируется просто отлично.
Я смущен точно, почему я могу перегрузить +=
и работать с ним нормально, в то время как перегрузка +
здесь не работает. Существует ли конкретное положение в стандарте, которое допускает инициализаторы, заключенные в скобки, в контексте оператора +=
, но не оператора +
? Или это просто странный компилятор причуды?
Ответы
Ответ 1
Это объясняется в ответе на этот вопрос (который связан с вопросом, с которым вы связались).
Языковая грамматика допускает только скопированный список в определенных грамматических контекстах, а не вместо произвольного выражения. Этот список включает правую часть операторов присваивания, но НЕ правую часть операторов вообще.
+=
является оператором присваивания, +
не является.
Грамматика для выражений присваивания:
Назначение выражение: условно-выражение логическое или выражение-присваивание-оператор-инициализатор-предложение вбрасывание выражение оператор присваивания: один из = *= *= /= %= += -= >>= <<= &= ^= |=
Ответ 2
С++ 14 §5.17/9:
" В правой части
может появиться список с привязкой к init-init, - присвоение скаляру, и в этом случае список инициализаторов должен иметь не более одного элемента. Значение
x={v}
, где T
является скалярным типом выражения x
, - это значение x=T{v}
. Значение x={}
составляет x=T{}
. - назначение объекту типа класса, и в этом случае список инициализаторов передается как аргумент функции оператора присваивания, выбранной с помощью разрешения перегрузки (13.5.3, 13.3).
Это относится к a +=
b через его эквивалентность $5.7/7 к =
a +
b (за исключением того, что a оценивается только один раз для +=
). Иными словами, из-за комментария М. М., из-за эквивалентности для встроенных операторов +=
рассматривается как оператор присваивания, а не специальный оператор обновления.
Следовательно, цитируемый текст выше о "присваивании" относится к +=
.
Ответ 3
Оператор +=
является составным назначением. Стандарт явно разрешает списки инициализаций в правой части назначений:
§8.5.4/1 [...] Примечание: можно использовать инициализацию списка
...
- в правой части присваивания (5.17)
В § 5.17 говорится обо всех заданиях, включая составные:
Назначение выражение:
- условное выражение
- назначение инициализатора логического или выражения-оператора
- throw-expression
оператор присваивания: один из
=
*=
/=
%=
+=
-=
>>=
<<=
&=
ˆ=
|=