💡 Кратко:Лямбды C++20 (часть 1): шаблонный синтаксис и ограничения типов, а также как deducing this из C++23 делает рекурсивные лямбды однострочником без std::function.
Последнее обновление:2026-10-24
Лямбда-выражения в C++20 (часть 1)¶
Шаблоны lambda в C++20¶
C++14 поддерживает обобщённые лямбда-выражения, что позволяет лямбде принимать параметры произвольных типов, например:
Оно разворачивается в:
struct Func {
template <typename T1, typename T2>
auto operator()(T1 a, T2 b) const {
return a + b;
}
};
Однако невозможно получить следующие варианты разворота:
Первый: одинаковые типы
Второй: только std::array
Третий: без выведения
Лямбды C++14 хороши, но C++20 позволяет легко реализовать и эти случаи. C++20 разрешает лямбда-выражениям использовать шаблонные типовые параметры в определении; базовый синтаксис таков:
Далее на нескольких примерах покажем, в чём выгода.
1.Ограничение типа¶
В примере наподобие приведённого ниже в C++14 мы могли бы написать такой код, однако при использовании передаваемое внутрь значение — не обязательно vector, и тогда поведение будет отличаться от ожидаемого, что приведёт к ошибкам.
После C++20 мы можем ограничить тип:
Тогда вопрос — интервью-задача: знаете ли вы, как в C++14 ограничиться vector'ом и при этом гарантировать безопасность?
2.Идеальная передача (perfect forwarding)¶
В C++20 вы можете очень легко использовать идеальную передачу, например:
Тогда вопрос: в чём преимущество по сравнению с C++14? Или иначе: что нужно было делать для реализации идеальной передачи в C++14?
На этом раздел закончен
Рекурсивные лямбды с deducing this (C++23)¶
Обычная лямбда не может назвать саму себя, поэтому рекурсия означала хранение лямбды в std::function (аллокация, косвенность) или обёртку в Y-комбинатор (остроумно, нечитаемо). Явные параметры объекта из C++23 — та же возможность deducing this — решают это изящно: лямбда принимает саму себя первым параметром:
// 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)
Параметр self выводится при каждом вызове, поэтому работает и обобщённая рекурсия: одна лямбда может рекурсировать по любому типу, а две лямбды способны вызывать друг друга, передавая себя. Поскольку компилятор видит сквозь self, эти вызовы встраиваются так, будто вы написали именованную функцию.
Поддержка: GCC 14+, Clang 18+, MSVC начиная с VS 2022 17.2 — компилируйте с -std=c++23.
Часто задаваемые вопросы¶
Как написать рекурсивную лямбду в C++?¶
С C++23 дайте лямбде явный параметр объекта: [](this auto self, int n) { ... self(n-1) ... }. Раньше — std::function, Y-комбинатор или просто именованная функция.
Рекурсивная лямбда с deducing this так же быстра, как обычная функция?¶
На практике да: компилятор специализирует вызов через self и может встроить его, в отличие от косвенного вызова std::function, который требовала рекурсия до C++23.
Работает ли deducing this с обобщёнными лямбдами?¶
Да. self выводится как auto&& при каждом вызове, поэтому одна лямбда рекурсирует по разным типам, а две лямбды даже могут вызывать друг друга, передавая себя.
Похожие темы¶
- Введение в корутины C++20 | C++那些事
- Практика с channel в C++20 | C++那些事
- Концепции Concepts в C++20 | C++那些事
- constexpr и оператор «запятая» в C++20 | C++那些事
- Порядок байтов endian в C++20 | C++那些事
- Модули Modules в C++20 | C++那些事
- Библиотека Ranges в C++20 | C++那些事
- Дизайн и подводные камни std::span в C++20 | C++那些事
- Обзор новых возможностей C++20 | C++那些事
- [[likely]] и [[unlikely]] в C++20 | C++那些事