C++11 значение-инициализация до агрегатной инициализации

Я пытаюсь понять первый принятый ответ @bolov на вопрос Удаленный конструктор по умолчанию. Объекты все еще могут быть созданы... иногда [1]

Кажется, что я нашел ошибку там, и поэтому это портит все объяснение.

@bolov объясняет, почему этот код ДОЛЖЕН быть скомпилирован в C++11:

Сценарий А

struct foo {
  foo() = delete;
};

// All bellow OK (no errors, no warnings)
foo f = foo{};
foo f = {};
foo f{}; // will use only this from now on.

И почему этот код не удается скомпилировать в C++11:

Сценарий С

struct foo {
  foo() = delete;
  foo(int) {};
};

foo f{}; // error call to deleted constructor

Он говорит, что дело в том, что первый foo - это совокупность, а второй - не совокупность.

Затем он дает отрывок из cppreference:

Эффекты инициализации списка объекта типа T:...

  • Если T является агрегатным типом, выполняется агрегатная инициализация. Это заботится о сценариях A B D E (и F в C++14)
  • В противном случае конструкторы T рассматриваются в два этапа:

    • Все конструкторы, которые принимают std::initializer_list ...

    • в противном случае [...] все конструкторы T участвуют в разрешении перегрузки [...] Это заботится о C (и F в C++11) ...

Согласно отрывку, когда вы пишете foo f { }; в сценарии A вы получаете агрегатную инициализацию. Это было бы здорово. Но в действительности в C++11 (черновик #3337, наиболее близкий к стандартному) у вас другой порядок инициализации:

Инициализация списка объекта или ссылки типа T определяется следующим образом:

  • Если список инициализаторов не имеет элементов и T является типом класса с конструктором по умолчанию, объект инициализируется значением.
  • В противном случае, если T является агрегатом, выполняется агрегатная инициализация (8.5.1)

Так что Foo F {}; в сценарии A это должно привести к инициализации значения, то есть будет вызван конструктор по умолчанию DELETED, и код не должен быть скомпилирован.

1 ответ

Решение

В результате основной проблемы 1301, которая была дефектом по сравнению с C++11, приоритет для инициализации списка изменился с:

Инициализация списка объекта или ссылки типа T определяется следующим образом:

  • Если список инициализаторов не имеет элементов и T является типом класса с конструктором по умолчанию, объект инициализируется значением.
  • В противном случае, если T является агрегатом, выполняется агрегатная инициализация (8.5.1)

чтобы:

Инициализация списка объекта или ссылки типа T определяется следующим образом:

  • Если T является агрегатом, выполняется агрегатная инициализация (8.5.1)
  • В противном случае, если список инициализации не имеет элементов и T является типом класса с конструктором по умолчанию, объект инициализируется значением.

Так foo{} в сценарии A все еще агрегатная инициализация.

Другие вопросы по тегам