C++ Generic lambdas



Lambda functions can take arguments of arbitrary types. This allows a lambda to be more generic:

auto twice = [](auto x){ return x+x; };

int i = twice(2); // i == 4
std::string s = twice("hello"); // s == "hellohello"

This is implemented in C++ by making the closure type's operator() overload a template function. The following type has equivalent behavior to the above lambda closure:

struct _unique_lambda_type
  template<typename T>
  auto operator() (T x) const {return x + x;}

Not all parameters in a generic lambda need be generic:

[](auto x, int y) {return x + y;}

Here, x is deduced based on the first function argument, while y will always be int.

Generic lambdas can take arguments by reference as well, using the usual rules for auto and &. If a generic parameter is taken as auto&&, this is a forwarding reference to the passed in argument and not an rvalue reference:

auto lamb1 = [](int &&x) {return x + 5;};
auto lamb2 = [](auto &&x) {return x + 5;};
int x = 10;
lamb1(x); // Illegal; must use `std::move(x)` for `int&&` parameters.
lamb2(x); // Legal; the type of `x` is deduced as `int&`.

Lambda functions can be variadic and perfectly forward their arguments:

auto lam = [](auto&&... args){return f(std::forward<decltype(args)>(args)...);};


auto lam = [](auto&&... args){return f(decltype(args)(args)...);};

which only works "properly" with variables of type auto&&.

A strong reason to use generic lambdas is for visiting syntax.

boost::variant<int, double> value;
apply_visitor(value, [&](auto&& e){
  std::cout << e;

Here we are visiting in a polymorphic manner; but in other contexts, the names of the type we are passing isn't interesting:

mutex_wrapped<std::ostream&> os = std::cout;
os.write([&](auto&& os){
  os << "hello world\n";

Repeating the type of std::ostream& is noise here; it would be like having to mention the type of a variable every time you use it. Here we are creating a visitor, but no a polymorphic one; auto is used for the same reason you might use auto in a for(:) loop.