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 все еще агрегатная инициализация.