Programando con C++20 (Parte II): Lambdas 'templatizadas'

Artículos de la serie:

Introducción


En C++20, las expresiones lambda genéricas pueden adoptar una sintaxis análoga a la de las plantillas de función (function templates) tradicionales [1]:
   [capture_list] <template_parameter_list>(optional C++20)  (parameters)(optional)    mutable-constexpr-consteval(optional)  noexcept(optional)       -> return_type(optional)       requires(optional C++20)    { body }

En la especificación general anterior, template_parameter_list es una lista no vacía de parámetros de plantilla --expresada entre llaves angulares-- que podemos emplear de forma opcional para dotar de nombres específicos a los parámetros de una expresión lambda genérica. Su inclusión vendrá acompañada típicamente por el uso de conceptos que impongan ligaduras sobre los tipos (cláusula requires).

Gracias a esta sintaxis, podemos requerir, por ejemplo, que varios argumentos de una lambda sean del mismo tipo genérico (en el código inferior, el tipo I se encuentra restringido por el concepto std::input_iterator):

   auto f = []<std::input_iterator I>(I first, I last) { /* ... */ };

Como ejemplo adicional, la siguiente lambda genérica opera únicamente con contenedores de tipo std::array:

   auto g = []<typename T, std::size_t N>(std::array<T, N>& m) { /* ... */ };

Referencias de reenvío y auto&&

Artículos de la serie:

Reglas de deducción de tipos


Dada una plantilla de función, una referencia de reenvío es una referencia rvalue a uno de los parámetros de la plantilla. Dicha referencia debe carecer, además, de calificadores const-volatile. A modo de ejemplo, consideremos la plantilla de función f siguiente:

template<typename T> void f(T&& t); // referencia de reenvío en la lista de parámetros de la función