Skip to content

Modern C++ • Generic (polymorphic) lambda expressions

C++11 has introduced a powerful long-awaited feature that greatly simplifies writing code that requires the use of closures, and that is lambda expressions. C++14 has further extended this feature by adding the ability to have automatically inferred types in the parameter list by using the auto specifier. Consider the following example

auto f = [](auto a, auto b) { return a + b; };

If we try to compile the above code with C++11 we would get an error about the parameters declaration. This is because C++11 does not support type inference in parameter lists. With C++14, instead, the above code is correct and compiles just fine. This means that lambda functions behave now in a “generic” manner and can be used, for example, in the following way

std::string cpp = "C++14 ", rocks = "rocks!";
auto f = [](auto a, auto b) { return a + b; };
auto sum1 = f(1, 2);        // sum1 = 3
auto sum2 = f(cpp, rocks);  // sum2 = "C++14 rocks!"

Should you have a deja vu at this point, don’t be puzzled. The above code is in fact equivalent to the following implementation

std::string cpp = "C++14 ", rocks = "rocks!";
 
struct f
{
    template<typename T>
    T operator()(T a, T b) const {
        return a + b;
    }
} f;
 
auto sum1 = f(1, 2);
auto sum2 = f(cpp, rocks);

adding the flexibility of generic programming with the power of closures. Another benefit of generic lambdas is that we don’t have to declare the type of the parameters using verbose syntax but just let the compiler do the job for us, like in the following example

std::map<std::string, std::vector<int>> m = ... ;
 
// C++11
std::for_each(begin(m), end(m),  [](const std::pair<std::string, std::vector<int>>& r)
{ /* ... */ });
 
// or
std::for_each(begin(m), end(m), [](const decltype(*begin(m))& r)
{ /* ... */ });
 
// C++14
std::for_each(begin(m), end(m), [](const auto& r)
{ /* ... */ });

Clearly an improvement over C++11.

Published inModern C++