Saltar a contenido

💡 Resumen:Lambda en C++20 (parte 1): sintaxis de plantillas y restricciones de tipo, y cómo el deducing this de C++23 convierte las lambdas recursivas en una línea sin std::function.

Última actualización:2026-10-24

Expresiones lambda de C++20 (parte 1)

Plantillas lambda en C++20

C++14 soporta expresiones lambda genéricas, lo que permite que una lambda acepte parámetros de cualquier tipo, por ejemplo:

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

Se expande a:

struct Func {
    template <typename T1, typename T2>
    auto operator()(T1 a, T2 b) const {
        return a + b;
    }
};

Pero no es capaz de lograr las siguientes expansiones:

Primera: el mismo tipo

template <class T>
auto operator()(T t1, T t2) const;

Segunda: solo std::array

template <class T, std::size_t N>
auto operator()(std::array<T, N> const &) const; 

Tercera: sin deducción

template <class T>
auto operator()() const;

Las lambdas de C++14 están muy bien, pero C++20 nos permite implementar estos casos con facilidad. C++20 permite que las expresiones lambda usen parámetros de tipo plantilla en su definición; he aquí la sintaxis básica:

[]<typename T>(){}

A continuación, varios ejemplos ilustran sus ventajas.

1.Restricción de tipos

En un ejemplo como el siguiente, en C++14 podríamos escribir este código, pero lo que se pasa al usarlo no tiene por qué ser un vector, de modo que el comportamiento se desviaría de lo esperado y produciría errores.

auto print = [](auto vec) {
  for (auto x : vec) {
    std::cout << x << std::endl;
  }
};

A partir de C++20, podemos restringir su tipo:

auto print2 = []<typename T>(std::vector<T>& vec){
    //使用 std::vector<T> 执行操作
};

Entonces surge la pregunta, y con ella una pregunta de entrevista: ¿sabes cómo garantizar la seguridad en C++14 para restringir un vector?

2.Reenvío perfecto

En C++20 puedes usar el reenvío perfecto con mucha facilidad, por ejemplo:

auto lambdaFunc = []<typename T>(T&& number) {
  processFunction(std::forward<T>(number));
};

Entonces la pregunta es: frente a C++14, ¿qué ventaja tiene? Dicho de otro modo, ¿qué hacía falta para implementar el reenvío perfecto en C++14?

Fin de esta sección

Lambdas recursivas con deducing this (C++23)

Una lambda normal no puede nombrarse a sí misma, así que la recursión significaba guardar la lambda en un std::function (asignación, indirección) o envolverla en un combinador-Y (ingenioso, ilegible). Los parámetros de objeto explícitos de C++23 —la misma característica deducing this— lo resuelven con elegancia: la lambda se recibe a sí misma como primer parámetro:

// C++23 explicit object parameter: the lambda receives itself
auto factorial = [](this auto self, int n) -> long long {
    return n <= 1 ? 1 : n * self(n - 1);
};

static_assert(factorial(10) == 3628800);

// before C++23 you needed std::function (heavy) or a Y-combinator (clever)

El parámetro self se deduce en cada llamada, así que la recursión genérica también funciona: una lambda puede recursar sobre cualquier tipo, y dos lambdas pueden llamarse mutuamente pasándose entre sí. Como el compilador ve a través de self, estas llamadas se inlinean como si hubieras escrito una función con nombre.

Soporte de compiladores: GCC 14+, Clang 18+, MSVC desde VS 2022 17.2 — compila con -std=c++23.

Preguntas frecuentes

¿Cómo escribo una lambda recursiva en C++?

Desde C++23, dale un parámetro de objeto explícito: [](this auto self, int n) { ... self(n-1) ... }. Antes, toca std::function, un combinador-Y, o simplemente una función con nombre.

¿La lambda recursiva con deducing this es tan rápida como una función normal?

En la práctica, sí: el compilador especializa la llamada a través de self y puede inlinearla, a diferencia de la llamada indirecta de std::function que exigía la recursión pre-C++23.

¿Funciona deducing this con lambdas genéricas?

Sí. self se deduce como auto&& en cada llamada, así que la misma lambda recursa sobre distintos tipos, y dos lambdas pueden incluso llamarse mutuamente pasándose entre sí.

Temas relacionados

Comentarios