S()
и S{}
означают одно и то же почти во всех случаях. Но не все случаи.
- Если
S
не тип класса, то же самое: инициализация значения. Если S
является типом класса, который является , а не агрегатом, в большинстве случаев это означает то же самое: инициализация значения. За исключением случаев, таких как:
struct X { X(std::initializer_list<int>); };
auto x1 = X(); // ill-formed
auto x2 = X{}; // ok, calls constructor
, если S
является агрегатом, то S()
является инициализацией значения, но S{}
агрегированием-инициализацией. Даже это означает одно и то же много времени. Но не всегда.
Пример 1: явный конструктор по умолчанию делает агрегатную инициализацию некорректной
struct A { explicit A(int = 0); };
struct B { A a; };
B b; // OK
B b2 = B(); // OK
B b3{}; // error through trying to copy-list-initialize a = {}
Пример 2: инициализация значения в некоторых контекстах сначала выполняет нулевую инициализацию
struct C { C() {} int i; };
struct D { C a; };
D d1{}; // d1.a.i is indeterminate
D d2 = D(); // d2.a.i is zero
В примере OP, хотя S
является агрегатом с неявно определенным конструктором по умолчанию - это интересный случай. Но здесь нет никаких изменений в семантике с дополнительной инициализацией нуля, мы инициализируем x
в 42
и строим по умолчанию v
в любом случае.
Обратите внимание, что также в OP это вызывает (и предназначено для вызова) оператор присваивания перемещения из S{}
:
value = { };
также возможно, что это может вызвать другой оператор полностью, так как {}
может в конечном итоге связать «лучше» с каким-то другим параметром в другой перегрузке оператора присваивания. std::optional
должен перепрыгнуть через несколько хуков, чтобы opt = {}
действительно вызывал оператор присваивания перемещения.