¿Cuál es la necesidad de la plantilla lambda introducida en C++ 20 cuando C++ 14 ya tiene lambda genérica?
c++14 c++20 (4)
c ++ 14 introdujo lambdas genéricas que permitieron escribir lo siguiente:
auto func = [](auto a, auto b){
return a + b;
};
auto Foo = func(2, 5);
auto Bar = func("hello", "world");
Es muy claro que esta
func
lambda genérica
func
misma manera que una función de
func
plantilla funcionaría.
¿Por qué el comité de C ++ decidió agregar la sintaxis de la plantilla para la lamda genérica?
La nueva "sintaxis de plantilla familiar" para las lambdas introducida en C ++ 20 hace que las construcciones como
for_types
yfor_range
viables y mucho más legibles en comparación con las alternativas de C ++ 17.
(fuente: iteración en tiempo de compilación con C ++ 20 lambdas )
Otra cosa interesante que se puede hacer con las lambdas genéricas de C ++ 14 y C ++ 17 es llamar directamente al
operator()
al pasar explícitamente un parámetro de plantilla:
C ++ 14:
auto l = [](auto){ };
l.template operator()<int>(0);
C ++ 20:
auto l = []<typename T>(){ };
l.template operator()<int>();
El ejemplo anterior de C ++ 14 es bastante inútil: no hay manera de referirse al tipo proporcionado a
operator()
en el cuerpo de la lambda sin dar un nombre al argumento y usar
decltype
.
Además, nos vemos obligados a pasar una discusión aunque no la necesitemos.
El ejemplo de C ++ 20 muestra cómo T es fácilmente accesible en el cuerpo de la lambda y que un lambda nulo ahora puede ser arbitrariamente arbitrado. Esto será muy útil para la implementación de las construcciones en tiempo de compilación mencionadas anteriormente.
La proposal que fue aceptada en C ++ 20 tiene una larga sección de motivación, con ejemplos. La premisa de esto es esta:
Hay algunas razones clave por las que el autor considera que la sintaxis actual para definir lambdas genéricas es insuficiente. La esencia de esto es que algunas cosas que se pueden hacer fácilmente con las plantillas de funciones normales requieren que se realicen importantes saltos de aro con lambdas genéricas, o no se pueden hacer en absoluto. Así como las plantillas de funciones normales.
A continuación hay algunos ejemplos.
Las lambdas genéricas de C ++ 14 son una forma genial de generar un functor con un
operator ()
que se parece a esto:
template <class T, class U>
auto operator()(T t, U u) const;
Pero no así:
template <class T>
auto operator()(T t1, T t2) const; // Same type please
Tampoco así:
template <class T, std::size_t N>
auto operator()(std::array<T, N> const &) const; // Only `std::array` please
Tampoco de esta manera (aunque esto es un poco difícil de usar):
template <class T>
auto operator()() const; // No deduction
Las lambdas de C ++ 14 están bien, pero C ++ 20 nos permite implementar estos casos sin problemas.
Ya que puedes usar lambdas templadas en C ++ 20, puedes restringir tus tipos de una manera más fácil que una expresión SFINAE:
auto lambda = []<typename T>(std::vector<T> t){};
Esta lambda funcionará solo con tipos de vectores.