C++ Template Lambdas | Explicit Template Parameters in C++20 Lambdas

C++ Template Lambdas | Explicit Template Parameters in C++20 Lambdas

이 글의 핵심

Template lambdas add explicit template parameters to lambdas so you can enforce same-type parameters, use concepts, and write pack-friendly lambdas.

Introduction

C++20 template lambdas let you specify explicit template parameters on a lambda, giving you precise control and clean concept-based constraints.


1. Basics: auto vs template lambda

#include <iostream>
#include <typeinfo>

int main() {
    // C++14: generic lambda
    auto addAuto =  {
        return a + b;
    };
    
    // C++20: template lambda — both parameters share T
    auto addTemplate = []<typename T>(T a, T b) {
        return a + b;
    };
    
    std::cout << addTemplate(1, 2) << std::endl;
    std::cout << addTemplate(1.5, 2.5) << std::endl;
    // addTemplate(1, 2.5);  // error: mismatched T
}

Printing with type info

auto print = []<typename T>(const T& value) {
    std::cout << "type: " << typeid(T).name()
              << ", value: " << value << std::endl;
};

Ideas

  • Explicit template parameters: <typename T>
  • Enforce relationships between parameters
  • Combine with concepts

2. Concepts

#include <concepts>

auto addInts = []<std::integral T>(T a, T b) {
    return a + b;
};

auto addFloats = []<std::floating_point T>(T a, T b) {
    return a + b;
};

Custom concepts

template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;

auto multiply = []<Numeric T>(T a, T b) {
    return a * b;
};

3. Practical examples

Example 1: Multiple template parameters

#include <iostream>

int main() {
    auto convert = []<typename From, typename To>(From value) {
        return static_cast<To>(value);
    };
    
    auto result1 = convert.operator()<int, double>(10);
    std::cout << result1 << std::endl;
    
    auto result2 = convert.operator()<double, int>(3.14);
    std::cout << result2 << std::endl;
    
    auto toInt = []<typename From>(From value) {
        return static_cast<int>(value);
    };
    
    std::cout << toInt(3.14) << std::endl;
}

Example 2: Containers

#include <iostream>
#include <vector>
#include <list>
#include <typeinfo>

int main() {
    auto printContainer = []<typename Container>(const Container& c) {
        using ValueType = typename Container::value_type;
        
        std::cout << "container: " << typeid(Container).name() << std::endl;
        std::cout << "value_type: " << typeid(ValueType).name() << std::endl;
        std::cout << "elements: ";
        
        for (const auto& item : c) {
            std::cout << item << " ";
        }
        std::cout << std::endl;
    };
    
    std::vector<int> vec = {1, 2, 3, 4, 5};
    printContainer(vec);
    
    std::list<double> lst = {1.1, 2.2, 3.3};
    printContainer(lst);
}

Example 3: Parameter packs

#include <iostream>

int main() {
    auto sum = []<typename... Ts>(Ts... values) {
        return (values + ...);
    };
    
    std::cout << sum(1, 2, 3) << std::endl;
    std::cout << sum(1.5, 2.5, 3.5) << std::endl;
    
    auto print = []<typename... Ts>(Ts... values) {
        ((std::cout << values << " "), ...);
        std::cout << std::endl;
    };
    
    print(1, 2, 3);
    print("Hello", 42, 3.14);
}

Example 4: Container transform

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    auto transform = []<typename Container, typename Func>(
        const Container& input, 
        Func func
    ) {
        using ValueType = typename Container::value_type;
        Container output;
        
        for (const auto& item : input) {
            output.push_back(func(item));
        }
        
        return output;
    };
    
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    auto doubled = transform(numbers, [](int x) { return x * 2; });
    
    for (int n : doubled) {
        std::cout << n << " ";
    }
    std::cout << std::endl;
}

Summary

  1. Template lambdas are C++20.
  2. Concepts constrain T (std::integral, custom concepts).
  3. Packs work: []<typename... Ts>(Ts... values).
  4. Explicit calls: .operator()<int>(...).

auto vs template lambda

Scenarioauto lambdaTemplate lambda
Independent parameter types❌ (unless multiple Ts)
Same T for multiple parameters
Concepts on T
Explicit template args

  • Generic lambda
  • constexpr lambda
  • Concepts

Keywords

C++, template lambda, C++20, concepts, generic lambda.

See also

  • auto type deduction