CodeNebula
C++20coreadvanced

Lambda Improvements (C++20 Evolution)

C++20 · The Big Four · Compiler flag: -std=c++20

Explanation

Lambdas support `constexpr`, explicit template parameters, and capture of `this` by value.

Real-World Scenario

Use a lambda in a compile-time context for a math library.

Quick Snippet

snippet.cpp
constexpr auto lambda = []<typename T>(T x) { return x * x; };

Full Example

lambda_enhancements.cpp
// CodeNebula - C++20 Example: Lambda Enhancements
// Compile: g++ -std=c++20 -Wall -Wextra -o example lambda_enhancements.cpp

// Demonstrates C++20 lambda improvements: template parameters, default
// constructible stateless lambdas, lambdas in unevaluated contexts,
// pack expansion captures, and implicit this capture deprecation.

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <type_traits>

int main()
{
    // ------------------------------------------------------------------
    // 1. Template lambdas: []<typename T>(T x)
    // ------------------------------------------------------------------
    std::cout << "=== Template Lambdas ===" << std::endl;
    auto typed_print = []<typename T>(const T& val) {
        if constexpr (std::is_integral_v<T>)
            std::cout << "  Integer: " << val << std::endl;
        else if constexpr (std::is_floating_point_v<T>)
            std::cout << "  Float: " << val << std::endl;
        else
            std::cout << "  Other: " << val << std::endl;
    };
    typed_print(42);
    typed_print(3.14);
    typed_print(std::string("hello"));

    // ------------------------------------------------------------------
    // 2. Template lambda with explicit type
    // ------------------------------------------------------------------
    std::cout << "\n=== Template Lambda with Vector ===" << std::endl;
    auto print_vec = []<typename T>(const std::vector<T>& v) {
        std::cout << "  [";
        for (std::size_t i = 0; i < v.size(); ++i) {
            if (i > 0) std::cout << ", ";
            std::cout << v[i];
        }
        std::cout << "]" << std::endl;
    };
    print_vec(std::vector<int>{1, 2, 3});
    print_vec(std::vector<std::string>{"a", "b", "c"});

    // ------------------------------------------------------------------
    // 3. Stateless lambdas are default constructible
    // ------------------------------------------------------------------
    std::cout << "\n=== Default Constructible Lambdas ===" << std::endl;
    auto cmp = [](int a, int b) { return a > b; };
    using CmpType = decltype(cmp);

    // Can default-construct the same lambda type
    CmpType cmp2{};
    std::vector<int> nums = {5, 2, 8, 1, 9};
    std::sort(nums.begin(), nums.end(), cmp2);
    std::cout << "  Sorted desc:";
    for (int n : nums) std::cout << " " << n;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 4. Lambda in unevaluated contexts (decltype, sizeof)
    // ------------------------------------------------------------------
    std::cout << "\n=== Lambda in Unevaluated Context ===" << std::endl;
    using AddType = decltype([](int a, int b) { return a + b; });
    AddType adder;  // Default construct from unevaluated lambda type
    std::cout << "  adder(3, 4) = " << adder(3, 4) << std::endl;

    // ------------------------------------------------------------------
    // 5. Pack expansion in lambda init-captures
    // ------------------------------------------------------------------
    std::cout << "\n=== Pack Expansion Capture ===" << std::endl;
    auto make_tuple_printer = [](auto... args) {
        return [... captured = args]() {
            ((std::cout << "  " << captured << std::endl), ...);
        };
    };
    auto printer = make_tuple_printer(1, 2.5, "three");
    printer();

    // ------------------------------------------------------------------
    // 6. Lambdas with constexpr and consteval
    // ------------------------------------------------------------------
    std::cout << "\n=== Constexpr Lambda ===" << std::endl;
    constexpr auto square = [](int x) { return x * x; };
    constexpr int result = square(7);
    std::cout << "  square(7) = " << result << std::endl;

    static_assert(square(5) == 25, "compile-time check");
    std::cout << "  static_assert(square(5) == 25) passed" << std::endl;

    // ------------------------------------------------------------------
    // 7. Lambda with explicit return type and template
    // ------------------------------------------------------------------
    std::cout << "\n=== Template Lambda with Explicit Return ===" << std::endl;
    auto safe_div = []<typename T>(T a, T b) -> T {
        return (b != T{}) ? a / b : T{};
    };
    std::cout << "  10 / 3 = " << safe_div(10, 3) << std::endl;
    std::cout << "  10.0 / 3.0 = " << safe_div(10.0, 3.0) << std::endl;
    std::cout << "  5 / 0 = " << safe_div(5, 0) << std::endl;

    return 0;
}

/*
Expected output:

=== Template Lambdas ===
  Integer: 42
  Float: 3.14
  Other: hello

=== Template Lambda with Vector ===
  [1, 2, 3]
  [a, b, c]

=== Default Constructible Lambdas ===
  Sorted desc: 9 8 5 2 1

=== Lambda in Unevaluated Context ===
  adder(3, 4) = 7

=== Pack Expansion Capture ===
  1
  2.5
  three

=== Constexpr Lambda ===
  square(7) = 49
  static_assert(square(5) == 25) passed

=== Template Lambda with Explicit Return ===
  10 / 3 = 3
  10.0 / 3.0 = 3.33333
  5 / 0 = 0
*/
Run command
g++ -std=c++20 -Wall -Wextra -o example lambda_enhancements.cpp