0

Удален конструктор по умолчанию. Объекты все еще могут быть созданы... иногда

8

Наивное, оптимистичное и... совершенно ошибочное представление о синтаксисе унифицированной инициализации в 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)`

0 ответ(ов)

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь