Why this code is not valid?
auto foo = [] () { return {1, 2}; };
However, this is valid since the initializer_list
is used just to initialize a vector
not to return itself:
auto foo = [] () -> std::vector<int> { return {1, 2}; };
Why I can not return initializer_list
? It could be useful. For example, a lambda that can be used to initialize a vector
or a list
or ... with some default values for something.
Lambda return type deduction uses the auto
rules, which normally would have deduced std::initializer_list
just fine. However, the language designers banned deduction from a braced initializer list in a return statement ([dcl.spec.auto]/7):
If the deduction is for a
return
statement and the initializer is a braced-init-list ([dcl.init.list]), the program is ill-formed.
The reason for this is that std::initializer_list
has reference semantics ([dcl.init.list]/6). []() -> std::initializer_list<int> { return {1, 2}; }
is every bit as bad as []() -> const int & { return 1; }
. The lifetime of the backing array of the initializer_list
object ends when the lambda returns, and you are left with a dangling pointer (or two).
Demo:
#include <vector> struct Noisy { Noisy() { __builtin_printf("%s\n", __PRETTY_FUNCTION__); } Noisy(const Noisy&) { __builtin_printf("%s\n", __PRETTY_FUNCTION__); } ~Noisy() { __builtin_printf("%s\n", __PRETTY_FUNCTION__); } }; int main() { auto foo = []() -> std::initializer_list<Noisy> { return {Noisy{}, Noisy{}}; }; std::vector<Noisy> bar{foo()}; }
Output:
Noisy::Noisy() Noisy::Noisy() Noisy::~Noisy() Noisy::~Noisy() Noisy::Noisy(const Noisy&) Noisy::Noisy(const Noisy&) Noisy::~Noisy() Noisy::~Noisy()
Note how the copy constructors are called after all the Noisy
objects created so far have been destroyed already.
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