Search code examples
c++lambdasyntactic-sugarc++14generic-lambda

Generic lambdas: syntactic sugar or not?


Do C++14 generic lambdas bring a real improvement to the language or they are a kind of syntactic sugar? Whether there are some situations where

[](auto param1, auto param2, /* ... */ auto paramN)
{
    return /* ... */;
}

cannot be replaced with

template <typename Type1, typename Type2, /* ... */ typename TypeN>
auto foo(Type1&& param1, Type2&& param2, /* ... */ TypeN&& paramN)
{
    return  /* ... */;
}

or

struct bar
{
    template <typename Type1, typename Type2, /* ... */ typename TypeN>
    auto operator()(Type1&& param1, Type2&& param2, /* ... */ TypeN&& paramN)
    {
        return  /* ... */;
    }
};

?


@Kerrek SB provided very interesting links in the comments which illustrate the power of generic lambdas:


Solution

  • For the non-generic lambda expressions of C++11, there is a somewhat straightforward translation that can be performed:

    void foo()
    {
        int i = 42; int j = 22;
        auto f = [i, &j](int k) { return i + j + k };
        // proceed to use f
     }
    

    For instance:

    void foo()
    {
        int i = 42; int j = 22;
        struct {
            int i; int& j;
            // can't deduce return type
            int operator()(int k) const
            { return i + j + k; }
        } f { i, j };
        // proceed to use f
    }
    

    For the generic lambda expressions of C++14, it’s not so straightforward. Suppose this time we’re using auto f = [i, &j](auto k) { return i + j + k; }. Then we must produce the following call operator:

    template<typename T>
    auto operator()(T k) const { return i + j + k; }
    

    The problem is that we cannot define a template at function scope (a restriction also known as no local templates). So we must move out the closure type definition out of the enclosing function to namespace scope (giving it a name in the process), then use closure_type f { i, j };. Incidentally this means we have to give the class and its operator some form of linkage, whereas function local definitions have no linkage.

    So in a sense, generic lambda expressions give us a limited version of local function templates.