Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A C++ template lambda is a lambda expression that explicitly declares a template parameter list, introduced in C++20. It extends the C++14 generic lambda (which relies on auto parameters) by allowing developers to name the template parameters directly. This enables precise type constraints, exact type extraction, and simplified perfect forwarding without requiring decltype or std::decay_t boilerplate.

Syntax Anatomy

The template parameter list is enclosed in angle brackets < > and is positioned immediately after the capture clause [ ] and before the function parameter list ( ).
[captures] <template_parameters> requires_clause (parameters) specifiers exception_attr -> return_type requires_clause { 
    // body 
}
Basic Example:
auto explicit_generic = []<typename T>(T a, T b) {
    return a + b;
};

Compiler Translation (The Closure Class)

Under the hood, the compiler translates a template lambda into an unnamed closure class containing a templated operator(). The lambda expression above is functionally equivalent to the following compiler-generated structure:
struct UnnamedClosureClass {
    template <typename T>
    auto operator()(T a, T b) const {
        return a + b;
    }
};
auto explicit_generic = UnnamedClosureClass{};

Technical Mechanics vs. C++14 Generic Lambdas

In C++14, generic lambdas use auto to deduce types, which implicitly creates a template parameter for each auto argument. C++20 template lambdas solve specific mechanical limitations of the auto approach.

1. Enforcing Identical Types

With C++14 generic lambdas, enforcing that two parameters share the exact same type requires static_assert and type traits. Template lambdas enforce this at the signature level.
// C++14: Implicitly creates <typename T1, typename T2>
auto cpp14_lambda = [](auto a, auto b) {
    static_assert(std::is_same_v<decltype(a), decltype(b)>);
};

// C++20: Explicitly creates <typename T>
auto cpp20_lambda = []<typename T>(T a, T b) {
    // a and b are guaranteed to be the same type
};

2. Perfect Forwarding

Forwarding an auto parameter in C++14 requires decltype to deduce the value category. Template lambdas allow direct use of the named template parameter T.
// C++14
auto forward_cpp14 = [](auto&& arg) {
    return wrapper(std::forward<decltype(arg)>(arg));
};

// C++20
auto forward_cpp20 = []<typename T>(T&& arg) {
    return wrapper(std::forward<T>(arg));
};

3. Extracting Inner Types

When passing a templated container (like std::vector) to a lambda, C++14 requires typename decltype(container)::value_type to access the underlying element type. Template lambdas allow pattern matching on the parameter type directly.
// C++14
auto process_cpp14 = [](const auto& container) {
    using ElementType = typename std::decay_t<decltype(container)>::value_type;
    ElementType temp = /* ... */;
};

// C++20
auto process_cpp20 = []<typename T>(const std::vector<T>& container) {
    T temp = /* ... */; // T is directly accessible
};

Integration with C++20 Concepts

Template lambdas natively support C++20 Concepts for constrained template parameters. The constraints can be applied directly in the template parameter list or via a requires clause.
// Constrained via concept in the template parameter list
auto constrained_lambda = []<std::integral T>(T value) {
    return value * 2;
};

// Constrained via trailing requires clause
auto requires_lambda = []<typename T>(T value) requires std::floating_point<T> {
    return value * 2.0;
};

Parameter Pack Support

Template lambdas fully support variadic template parameter packs, allowing the lambda to accept an arbitrary number of arguments of varying types while retaining the ability to expand the pack explicitly.
auto variadic_lambda = []<typename... Args>(Args&&... args) {
    return (std::forward<Args>(args) + ...); // Fold expression
};
Master C++ with Deep Grasping Methodology!Learn More