C++ Lambdas genericas


Ejemplo

c ++ 14

Las funciones Lambda pueden tomar argumentos de tipos arbitrarios. Esto permite que un lambda sea más genérico:

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

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

Esto se implementa en C ++ al hacer que el operator() de tipo de cierre operator() sobrecargue una función de plantilla. El siguiente tipo tiene un comportamiento equivalente al cierre lambda anterior:

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

No todos los parámetros en un lambda genérico necesitan ser genéricos:

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

Aquí, x se deduce en función del primer argumento de la función, mientras que y siempre será int .

Las lambdas genéricas también pueden tomar argumentos por referencia, usando las reglas habituales para auto y & . Si un parámetro genérico se toma como auto&& , esta es una referencia de reenvío al argumento pasado y no una referencia de rvalue :

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&`.

Las funciones Lambda pueden ser variadas y perfectamente remiten sus argumentos:

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

o:

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

que solo funciona "correctamente" con variables de tipo auto&& .

Una razón importante para usar lambdas genéricas es para visitar la sintaxis.

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

Aquí estamos visitando de manera polimórfica; pero en otros contextos, los nombres del tipo que estamos pasando no son interesantes:

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

Repitiendo el tipo de std::ostream& is noise here; Sería como tener que mencionar el tipo de variable cada vez que la uses. Aquí estamos creando un visitante, pero no polimórfico; auto se utiliza por el mismo motivo por el que puede usar auto en un bucle for(:) .