Удален конструктор по умолчанию. Объекты все еще могут быть созданы... иногда
Наивное, оптимистичное и... совершенно ошибочное представление о синтаксисе унифицированной инициализации в C++11
Я думал, что с введением C++11 объекты пользовательских типов должны создаваться с помощью нового синтаксиса {...}
, вместо старого (...)
(за исключением конструкторов, перегруженных на std::initializer_list
и подобных параметрах (например, std::vector
: конструктор размера и конструктор с одним элементом init_list)).
Преимущества этого подхода: отсутствие узких неявных преобразований, никаких проблем с "самым раздражающим парсингом", последовательность (?). Я не видел проблем, так как думал, что они эквивалентны (за исключением приведенного примера).
Но это не так.
Сказание о чистом безумии
Синтаксис {}
вызывает конструктор по умолчанию.
... Кроме случаев, когда:
- конструктор по умолчанию удален и
- другие конструкторы не определены.
Тогда, похоже, он скорее значение инициализирует объект?... Даже если у объекта имеется удаленный конструктор по умолчанию, {}
может создать объект. Разве это не противоречит самой сути удаленного конструктора?
...Кроме случаев, когда:
- у объекта удален конструктор по умолчанию и
- определены другие конструкторы.
Тогда возникает ошибка вызов удаленного конструктора
.
...Кроме случаев, когда:
- у объекта удален конструктор и
- другие конструкторы не определены и
- имеется хотя бы один нестатический член данных.
Тогда возникает ошибка из-за отсутствия инициализаторов полей.
Но тогда вы можете использовать {value}
для создания объекта.
Хорошо, возможно, это то же самое, что и первый случай (значение инициализирует объект)
...Кроме случаев, когда:
- класс имеет удаленный конструктор и
- по крайней мере один член данных инициализирован по умолчанию в классе.
В этом случае ни {}
, ни {value}
не могут создать объект.
Я уверен, что я упустил еще некоторые случаи. Ирония в том, что это называется унифицированный синтаксис инициализации. Я повторяю: УНИФИЦИРОВАННЫЙ синтаксис инициализации.
Что это за безумие?
Сценарий A
Удаленный конструктор по умолчанию:
struct foo {
foo() = delete;
};
// Все ниже ОК (без ошибок и предупреждений)
foo f = foo{};
foo f = {};
foo f{}; // буду использовать только это с этого момента.
Сценарий B
Удаленный конструктор по умолчанию, другие конструкторы удалены
struct foo {
foo() = delete;
foo(int) = delete;
};
foo f{}; // ОК
Сценарий C
Удаленный конструктор по умолчанию, другие конструкторы определены
struct foo {
foo() = delete;
foo(int) {};
};
foo f{}; // ошибка при вызове удаленного конструктора
Сценарий D
Удаленный конструктор по умолчанию, другие конструкторы не определены, член данных
struct foo {
int a;
foo() = delete;
};
foo f{}; // ошибка: использование удаленной функции foo::foo()
foo f{3}; // ОК
Сценарий E
Удаленный конструктор по умолчанию, удаленный конструктор T, член данных T
struct foo {
int a;
foo() = delete;
foo(int) = delete;
};
foo f{}; // ОШИБКА: отсутствует инициализатор
foo f{3}; // ОК
Сценарий F
Удаленный конструктор по умолчанию, инициализаторы членов данных в классе
struct foo {
int a = 3;
foo() = delete;
};
/* Fa */ foo f{}; // ОШИБКА: использование удаленной функции `foo::foo()`
/* Fb */ foo f{3}; // ОШИБКА: нет соответствующей функции для вызова `foo::foo(init list)`
Правила использования символа подчеркивания в идентификаторах C++
Что говорит стандарт C++ о размерах типов int и long?
Каковы преимущества инициализации списка (с использованием фигурных скобок)?
Что такое Правило трёх?
Разница между const int*, const int * const и int * const?