10

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?

a.lasram
  • 4,371
  • 1
  • 16
  • 24
  • Did you try `auto z = []() -> auto { return {0}; }();`? – Mark B Jun 29 '13 at 20:05
  • 2
    Note that you do **not** want it to deduce `initializer_list` anyway, because the values in the list have lifetime of the lambda - they're not extended by a function return. They are destroyed before you could use `y` or `z`. [More info](http://stackoverflow.com/questions/15286450/lifetime-of-a-stdinitializer-list-return-value). The `y` line causes UB. – M.M Feb 28 '15 at 00:18

2 Answers2

10

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>
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • Thanks Andy for the answer. I thought deduction for auto and templates follows the same rules but you're giving a counterexample. – a.lasram Jun 29 '13 at 20:20
  • @a.lasram: They do in most situations, but there are exceptions. Actually, I think the one I pointed out at the end of the answer is the *only* exception - although I am not 100% sure. – Andy Prowl Jun 29 '13 at 20:22
  • @ Andy Prowl - sorry, same situation as auto: foo({1, 2}) fails but foo>({1, 2}) would pass. – a.lasram Jun 29 '13 at 20:30
  • @a.lasram: I understood what you meant ;) – Andy Prowl Jun 29 '13 at 20:31
1

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 for decltype. C++14 then extends the usage contexts in which auto and decltype 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, but auto type deduction assumes that a braced initializer represents a std::initializer_list and template type deduction doesn't.
  • auto in a function return type or a lambda parameter implies template type deduction, not auto 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 [...].

Maxim Chetrusca
  • 3,262
  • 1
  • 32
  • 28