In the following:
auto x = {0}; // auto deduction of std::initializer_list<int>
auto y = []() -> std::initializer_list<int> { return {0}; }(); //explicit
auto z = []() { return {0}; }(); // won't compile
why it's not possible to return and auto deduce the type of std::initializer_list?
Well, because the Standard says so, and because a braced-init-list is not an expression. Per paragraph 5.1.2/4 of the C++11 Standard:
[...] If a lambda-expression does not include a trailing-return-type, it is as if the trailing-return-type denotes the following type:
— if the compound-statement is of the form
{
attribute-specifier-seq(opt)return
expression; }
the type of the returned expression after lvalue-to-rvalue conversion (4.1), array-to-pointer conversion (4.2), and function-to-pointer conversion (4.3);
— otherwise,
void
.
The above makes it clear that the return type will be deduced to be anything else then void
if and only if the return
statement is followed by an expression, and a braced-init-list is not in itself an expression - it does not have a type, and it does not yield a value. It is just a language construct that can be used in the context of initialization.
The above paragraph also provides an example:
[ Example:
auto x1 = [](int i){ return i; }; // OK: return type is int auto x2 = []{ return { 1, 2 }; }; // error: the return type is void (a // braced-init-list is not an expression)
—end example ]
Finally, if the question is:
"Why a special rule was introduced for deducing the type of an auto
variable initialized from a braced-init-list, while a similar rule was not introduced for deducing the return type of a lambda when return
is followed by a braced-init-list?"
Then the question is not constructive. Also notice, that type deduction for templates does not work with braced-init-lists either:
template<typename T>
void foo(T);
foo({1, 2}); // ERROR! T is NOT deduced to be std::initializer_list<int>
I think the accepted answer makes perfect sense, but I would like to add a bit of context from "Effective Modern C++" by Scott Meyers:
C++98/03 had a single set of rules for type deduction: the one for function templates. C++11 modifies that ruleset a bit and adds two more, one for
auto
and one fordecltype
. C++14 then extends the usage contexts in whichauto
anddecltype
may be employed.[...]
Deducing types for
auto
is, with only one exception, the same as deducing types for templates.
auto
type deduction is usually the same as template type deduction, butauto
type deduction assumes that a braced initializer represents astd::initializer_list
and template type deduction doesn't.auto
in a function return type or a lambda parameter implies template type deduction, notauto
type deduction.You might wonder why
auto
type deduction has a special rule for braced initializers, but template type deduction does not. I wonder this myself. Alas, I have not been able to find a convincing explanation. But the rule is the rule [...].
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With