Почему я могу использовать списки инициализаций в правой части оператора + =, но не оператор +?

Это следующий вопрос более раннего вопроса о том, почему я не могу использовать инициализатор, заключенный в фигурные скобки, в качестве аргумента 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

оператор присваивания: один из
= *= /= %= += -= >>= <<= &= ˆ= |=