Инициализация значения C++14 с удаленным конструктором
У меня есть недоразумение:
Давайте отметим конструктор по умолчанию для структуры A как удаленный:
struct A
{
A() = delete;
};
Следующая инструкция правильно сформирована и что это за эффект?:
A a{};
Из инициализации значения cppreference:
1) Если T является типом класса без конструктора по умолчанию или с предоставленным пользователем конструктором по умолчанию или с удаленным конструктором по умолчанию, объект инициализируется по умолчанию.
но тогда эффект инициализации по умолчанию:
Если T является типом класса, конструктор по умолчанию вызывается для предоставления начального значения для нового объекта.
Или это совокупная инициализация? Спасибо!
2 ответа
Ваш struct A
является:
- тип класса, который имеет:
- нет пользовательских конструкторов1,
- нет частных или защищенных нестатических членов данных,
- нет базовых классов,
- нет виртуальных функций-членов.
Поэтому он квалифицируется как агрегатный тип в соответствии с определением, приведенным в п. 8.5.1/1.
Затем наступает приоритет инициализации агрегата над инициализацией значения. Стандарт гласит, что агрегатная инициализация имеет приоритет над инициализацией значения (черновик N3936, § 8.5.4/3, стр. 201) (выделено мной)
Инициализация списка объекта или ссылки типа T определяется следующим образом:
- Если T является агрегатом, выполняется агрегатная инициализация (8.5.1).
- В противном случае, если список инициализаторов не имеет элементов и T является типом класса с конструктором по умолчанию, объект инициализируется значением.
- [... больше правил...]
(1) В соответствии с запросом в комментариях о том, почему удаленный конструктор не считается пользовательским, вот что говорит стандарт (черновик N3936, § 8.4.2/5, стр. 198):
Функция предоставляется пользователем, если она объявлена пользователем и не имеет явных значений по умолчанию или удалена в первом объявлении.
Это хорошо сформировано. A
является агрегатом1, и, согласно проекту N3936, пустой список инициализатора, используемый при инициализации прямого списка агрегата, приводит к инициализации агрегата:
Из п. 8.5.4 / 3 List-initialization [dcl.init.list]:
Инициализация списка объекта или ссылки типа T определяется следующим образом:
- Если T является агрегатом, выполняется агрегатная инициализация (8.5.1).
[ Пример:
struct S2 { int m1; double m2, m3; };
....
S2 s23{}; // OK: default to 0,0,0
....
- конец примера]
....
Соответствующие изменения между C++11 и C++1y - это изменение приоритета инициализации агрегата по сравнению со значением для случая агрегатов:
C++11 ведет с
Инициализация списка объекта или ссылки типа T определяется следующим образом:
- Если список инициализаторов не имеет элементов и T является типом класса с конструктором по умолчанию, объект инициализируется значением.
- В противном случае, если T является агрегатом, выполняется агрегатная инициализация (8.5.1)....
сопровождаемый примером выше.
C++1y отдает приоритет агрегатной инициализации:
Инициализация списка объекта или ссылки типа T определяется следующим образом:
- Если T является агрегатом, выполняется агрегатная инициализация (8.5.1).
....
- В противном случае, если список инициализаторов не имеет элементов и T является типом класса с конструктором по умолчанию, объект инициализируется значением.
1 Почему A
совокупность?
Это совокупность как в C++11, так и в C++ 14.
C++1y:
8.5.1 Агрегаты [dcl.init.aggr]
Агрегат - это массив или класс (раздел 9) без предоставленных пользователем конструкторов (12.1), без закрытых или защищенных нестатических элементов данных (пункт 11), без базовых классов (пункт 10) и без виртуальных функций (10.3).
Единственная часть, которая не очевидна - это то, предоставлен конструктор по умолчанию или нет. Это не:
В § 8.4.2 [dcl.fct.def.default]:
Функция предоставляется пользователем, если она объявлена пользователем и не имеет явных значений по умолчанию или удалена в первом объявлении.