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
returnstatement 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