问题
There are a couple of differing styles when initializing automatically managed simple variables other than via assignment. I was wondering if there are any specific reasons to favour one over the other or is it just a matter of style.
Using parentheses is appealing because it feels similar to instantiating an object
double answer(42.0);
ComplexNumber i(0,1);
while using braces is appealing because it feels similar to initialising a container
double answer{42};
std::vector<double> i{0,1};
double i2[] = {0,1};
Is there any particular reason to favour one style over the other?
回答1:
Look here: GotW #1 : Variable Initialization. It's a detailed description of answer from H. Sutter.
H. Sutter talks above in a general sense of old and new styles of Variable Initialization.
Below is showed a quick synopsis from the article, according to your start-topic context.
This pair
double answer(42.0); // (1)
double answer{42}; // (2)
in fact, is similar to the next initialization example:
widget w(x); // (d)
widget w{x}; // (e)
These are both direct initialization. However, note that the syntax {x} creates an initializer_list. If widget has a constructor that takes an initializer_list, that constructor is preferred; otherwise, if widget has a constructor that takes whatever type x is (possibly with conversions), that constructor is used.
There are two major differences that make (2, e) superior to (1, d):
- First, syntax (2, e) is unambiguous and avoids the "vexing parse". If
xis a type name, then (1, d) is a function declaration even if there is also a variable namedxin scope (see above), whereas (2, e) is never a function declaration. Second, syntax (2, e) is safer because it does not allow narrowing (a.k.a. “lossy”) conversions that are otherwise allowed for some built-in types. Consider:
int i1( 12.345 ); // ok: toss .345, we didn't like it anywayint i2{ 12.345 }; // error: would be lossy implicit narrowing
Next pair
ComplexNumber i(0,1); // (3)
std::vector<double> i{0,1}; // (4)
is tied with initialization of complex objects. Both looks quite the same, but the second one helps us to avoid "vexing parse", like:
ComplexNumber w( real(), img() ); // oops, vexing parse
Besides of that, this way make code more clear (if we use initializer_list, it's more clear that's initialization),
and, moreover, alleviate syntax in some cases, for instance:
draw_rect({ origin, selection }); // C++11
Sutter guildeline is: prefer to use initialization with { }, such as vector<int> v = { 1, 2, 3, 4 }; or auto v = vector<int>{ 1, 2, 3, 4 };, because it’s more consistent, more correct, and avoids having to know about old-style pitfalls at all. In single-argument cases where you prefer to see only the = sign, such as int i = 42; and auto x = anything; omitting the braces is fine.
We can use ()-initialization for the explicit call of the special constructor.
回答2:
Adding to Boris's answer there's another pitfall to avoid that's not mentioned in Herb's blog post.
The following code is illegal:
#include <initializer_list>
int main() {
auto i{42}; // not the same as 'auto i(42);'
++i;
}
The error message raised by gcc 4.7.2 is:
error: no match for 'operator++' in '++i'
The reason is that auto deduces the type of {42} to be std::inilializer_list<int> rather than int as many could believe. There's no operator ++ for std::initializer_list<int> and hence the error. If you replace {42} with (42) then the code compiles fine.
回答3:
GotW #93 has a very interesting rationale for declaring everything with auto.
来源:https://stackoverflow.com/questions/17112692/c-style-for-the-initialization-of-single-variables