Search code examples
c++c++11lambdac++14initializer-list

Why I can not return initializer list from lambda


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.


Solution

  • 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.