I'm one Item away from having five full draft chapters for my book on effective use of C++11 and C++14. That's one Item away from being about 75% done. I'd really like to get that Item behind me.
The prospective Item title is "Distinguish () and {} when creating objects." I've put off writing it for months, because, frankly, I think the technical situation is a mess, and the advice I have isn't as helpful as I'd like. There are a number of aspects to the mess, but part of the problem is that a braced initializer such as "{ 10, 20, 30}" has no type, yet the C++11 and C++14 standards insist on deducing one for it. But only sometimes. Not always. Not for template arguments. Not for function return types. Not for auto parameters to lambda expressions. Only for auto variables. Which is why this is the case:
auto x = { 5 }; // "{ 5 }" has no type,
// but x's type is std::initializer_list
In this area, the standard makes no distinction between copy initialization (using "=", as in the example above) and direct initialization (without "=", as in the example on the next line), so:
auto y { 5 }; // y's type is also std::initializer_list
I've never understood why there's a special type deduction rule for braced initializers in the context of an auto variable, but, hey, I'm just a grunt on the ground. My job isn't to make the rules, it's to report them.
There's an Item in my draft book devoted to the interaction of auto variables and braced initializers, because that interaction confuses everybody. Even so-called experts like me and Herb Sutter have known the thrill of publishing blog posts with incorrect code, because we forgot that
int x1 = 5;
int x2(5);
int x3{ 5 };
int x4 = { 5 };
all do the same thing, but
auto x1 = 5; // deduced type is int
auto x2(5); // deduced type is int
auto x3{ 5 }; // deduced type is std::initializer_list
auto x4 = { 5 }; // deduced type is std::initializer_list
don't.
The committee is not unaware of this issue. The abstract for N3681 says, "This paper proposes
to change a brace-initialized
auto to not deduce to an initializer
list..." That is, it proposes getting rid of type deduction for a construct that doesn't have a type and thereby eliminating a provision of C++ that confuses everybody. (As you can probably tell, I'm in favor of this proposal.)
The successors to N3681,
N3912 and
N3922, propose getting rid of this behavior only for direct initialization, thus introducing, in my view, even more confusion into an area that already has plenty. Under the proposed new rules, this would be the situation:
auto x1 = 5; // deduced type is int
auto x2(5); // deduced type is int
auto x3{ 5 }; // deduced type is int
auto x4 = { 5 }; // deduced type is std::initializer_list
Can somebody please explain to me why it' s so important to have a special rule for deducing a type for a braced initializer list for
auto variables using copy initialization, but not important enough for
auto variables using direct initialization,
auto parameters to lambda expressions, or
auto function return types?
Scott