Short version
Initialization via {..}
is list-initialization, which prohibits narrowing conversions. For example, if LLONG_MAX
is the maximum value of an long long int
, and your int
cannot represent that:
int x = LLONG_MAX; // probably accepted with a warning
int x {LLONG_MAX}; // error
Similarly:
long long y = /*something*/;
int x = y; // accepted, maybe with a warning
int x {y}; // error
Long version
An initialization of the form
T x = a;
is copy-initialization; an initialization of either form
T x(a);
T x{a};
is direct-initialization, [dcl.init]/15-16.
[dcl.init]/14 then says:
The form of initialization (using parentheses or
=
) is generally insignificant, but does matter when the initializer or the entity being initialized has a class type; see below.
So for non-class types, the form of the initialization doesn’t matter. However, there’s a difference between these two direct-initializations:
T x(a); // 1
T x{a}; // 2
and similarly, between these two copy-initializations:
T x = a; // 1
T x = {a}; // 2
Namely, the ones with {..}
use list-initialization. The {..}
is called a braced-init-list.
So, when you compare T x = a;
to T x {a};
, there are two differences: copy- vs. direct-initialization, and “non-list-” vs. list-initialization. As already mentioned by others and in the quote above, for non-class types T
, there’s no difference between copy- and direct-init. However, there’s a difference between list-init and no list-init. That is, we could as well compare
int x (a);
int x {a};
List-initialization in this case prohibits narrowing conversions. Narrowing conversions are defined in [dcl.init.list]/7 as:
A narrowing conversion is an implicit conversion
from a floating-point type to an integer type, or
from
long double
todouble
orfloat
, or fromdouble
tofloat
, except where the source is a constant expression and the actual value after conversion is within the range of values that can be represented
(even if it cannot be represented exactly), orfrom an integer type or unscoped enumeration type to a floating-point type, except where the source
is a constant expression and the actual value after conversion will fit into the target type and will
produce the original value when converted back to the original type, orfrom an integer type or unscoped enumeration type to an integer type that cannot represent all the
values of the original type, except where the source is a constant expression whose value after integral
promotions will fit into the target type.