The C++ reference pages say that () is for value initialisation, {} is for value and aggregate and list initialisation. So, if I just want value initialisation, which one do
There is another important difference: The brace initializer requires that the given type can actually hold the given value. In other words, it forbids narrowing of the value, like rounding or truncation.
int a(2.3); // ok? a will hold the value 2, no error, maybe compiler warning
uint8_t c(256); // ok? the compiler should warn about something fishy going on
As compared to the brace initialization
int A{2.3}; // compiler error, because int can NOT hold a floating point value
double B{2.3}; // ok, double can hold this value
uint8_t C{256}; // compiler error, because 8bit is not wide enough for this number
Especially in generic programming with templates you should therefore use brace initialization to avoid nasty surprises when the underlying type does something unexpected to your input values.
{} is value initialization if empty, if not it is list/aggregate initialization.
From the draft, 7.1.6.4 auto specifier, 7/... Example,
auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>
Rules are a little bit complex to explain here (even hard to read from the source!).
Scott Mayers just posted a relevant blog entry Thoughts on the Vagaries of C++ Initialization. It seems that C++ still has a way to go before achieving a truly uniform initialization syntax.
First off, there seems to a terminology mixup. What you have is not value initialisation. Value initialisation happens when you do not provide any explicit initialisation arguments. int x;
uses default initialisation, the value of x
will be unspecified. int x{};
uses value initialisation, x
will be 0
. int x();
declares a function—that's why {}
is preferred for value initialisation.
The code you've shown does not use value initialisation. With auto
, the safest thing is to use copy initialisation:
auto q = p;
Herb Sutter seems to be making an argument in CppCon 2014 (39:25 into the talk) for using auto and brace initializers, like so:
auto x = MyType { initializers };
whenever you want to coerce the type, for left-to-right consistency in definitions:
auto x = getSomething()
auto x = MyType { blah }
auto x = "Hello, world."s
auto f { some; commands; } -> MyType
using auto f = [=]( { some; commands; } -> MyType
using AnotherType = SomeTemplate<MyTemplateArg>
Scott Meyers has a fair amount to say about the difference between the two methods of initialization in his book Effective Modern C++.
He summarizes both approaches like this:
Most developers end up choosing one kind of delimiter as a default, using the other only when they have to. Braces-by-default folks are attracted by their unrivaled breadth of applicability, their prohibition of narrowing conversions, and their immunity to C++’s most vexing parse. Such folks understand that in some cases (e.g., creation of a
std::vector
with a given size and initial element value), parentheses are required. On the other hand, the go-parentheses-go crowd embraces parentheses as their default argument delimiter. They’re attracted to its consistency with the C++98 syntactic tradition, its avoidance of the auto-deduced-a-std::initializer_list problem, and the knowledge that their object creation calls won’t be inadvertently waylaid bystd::initializer_list
constructors. They concede that sometimes only braces will do (e.g., when creating a container with particular values). There’s no consensus that either approach is better than the other, so my advice is to pick one and apply it consistently.