본문으로 건너뛰기 C++ constexpr Lambda | 'Compile-Time Lambda' Guide

C++ constexpr Lambda | 'Compile-Time Lambda' Guide

C++ constexpr Lambda | 'Compile-Time Lambda' Guide

이 글의 핵심

C++ constexpr Lambda: "Compile-Time Lambda" Guide. Constexpr lambda basics and compile-time calculation.

Introduction

C++17 constexpr lambda is a lambda expression executable at compile-time. Used for metaprogramming, compile-time calculation, type validation, etc., providing powerful features without runtime cost.


1. constexpr Lambda Basics

C++17 Implicit constexpr

#include <iostream>

// C++17: lambda implicitly constexpr
auto add = [](int a, int b) {
    return a + b;
};

int main() {
    // Compile-time use
    constexpr int result1 = add(3, 4);  // 7
    static_assert(add(3, 4) == 7);
    
    // Runtime use also possible
    int x = 10, y = 20;
    int result2 = add(x, y);  // 30
    
    std::cout << result1 << ", " << result2 << std::endl;
    return 0;
}

Key Concepts:

  • From C++17, lambdas are implicitly constexpr
  • Condition: lambda body satisfies constexpr requirements
  • Usable at both compile-time and runtime

Explicit constexpr

// Explicitly specify constexpr
constexpr auto square = [](int x) constexpr {
    return x * x;
};

constexpr int result = square(5);  // 25
static_assert(square(5) == 25);

// Use as array size
int arr[square(4)];  // Size 16

2. Compile-Time Calculation

Example 1: Factorial

#include <iostream>

constexpr auto factorial = [](int n) {
    int result = 1;
    for (int i = 2; i <= n; i++) {
        result *= i;
    }
    return result;
};

int main() {
    // Compile-time calculation
    constexpr int f5 = factorial(5);  // 120
    static_assert(factorial(5) == 120);
    
    // Use as array size
    int arr[factorial(4)];  // Size 24
    
    std::cout << "5! = " << f5 << std::endl;
    std::cout << "Array size: " << sizeof(arr) / sizeof(int) << std::endl;
    
    return 0;
}

Example 2: Power (Using Template)

#include <iostream>

template<int N>
constexpr auto power = [](int base) {
    int result = 1;
    for (int i = 0; i < N; i++) {
        result *= base;
    }
    return result;
};

int main() {
    constexpr int p2 = power<3>(2);  // 2^3 = 8
    constexpr int p3 = power<5>(3);  // 3^5 = 243
    
    static_assert(power<3>(2) == 8);
    static_assert(power<5>(3) == 243);
    
    std::cout << "2^3 = " << p2 << std::endl;
    std::cout << "3^5 = " << p3 << std::endl;
    
    return 0;
}

Example 3: Array Initialization

#include <array>
#include <iostream>

template<size_t N>
constexpr auto makeArray = []() {
    std::array<int, N> arr{};
    for (size_t i = 0; i < N; i++) {
        arr[i] = i * i;
    }
    return arr;
};

int main() {
    constexpr auto squares = makeArray<5>();
    // {0, 1, 4, 9, 16}
    
    for (int val : squares) {
        std::cout << val << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

3. Type Checking and Metaprogramming

Type Checking

#include <type_traits>
#include <iostream>

constexpr auto isIntegral = [](auto value) {
    return std::is_integral_v<decltype(value)>;
};

constexpr auto isFloating = [](auto value) {
    return std::is_floating_point_v<decltype(value)>;
};

int main() {
    static_assert(isIntegral(10));
    static_assert(!isIntegral(3.14));
    static_assert(isFloating(3.14));
    static_assert(!isFloating(10));
    
    std::cout << "Type check passed" << std::endl;
    return 0;
}

Conditional Compilation

#include <type_traits>
#include <iostream>

constexpr auto processValue = [](auto value) {
    if constexpr (std::is_integral_v<decltype(value)>) {
        return value * 2;
    } else if constexpr (std::is_floating_point_v<decltype(value)>) {
        return value * 1.5;
    } else {
        return value;
    }
};

int main() {
    constexpr int i = processValue(10);      // 20
    constexpr double d = processValue(10.0); // 15.0
    
    static_assert(i == 20);
    static_assert(d == 15.0);
    
    std::cout << i << ", " << d << std::endl;
    return 0;
}

4. Constraints

What’s Allowed

// ✅ Allowed: basic operations
constexpr auto add = [](int a, int b) { return a + b; };

// ✅ Allowed: loops
constexpr auto sum = [](int n) {
    int result = 0;
    for (int i = 1; i <= n; i++) {
        result += i;
    }
    return result;
};

// ✅ Allowed: recursion
constexpr auto fibonacci = [](int n) {
    auto fib = [](int n, auto& self) -> int {
        if (n <= 1) return n;
        return self(n - 1, self) + self(n - 2, self);
    };
    return fib(n, fib);
};

// ✅ Allowed: capture (C++17)
constexpr int x = 10;
constexpr auto addX = [x](int y) { return x + y; };

What’s Not Allowed

Here is the nonConstexpr implementation:

// ❌ Not allowed: non-constexpr function call
int nonConstexpr(int x) { return x * 2; }
constexpr auto bad1 = [](int x) {
    return nonConstexpr(x);  // Error
};

// ❌ Not allowed: static variable (C++17)
constexpr auto bad2 = []() {
    static int count = 0;  // Error
    return count++;
};

// ❌ Not allowed: dynamic allocation
constexpr auto bad3 = []() {
    int* p = new int(10);  // Error
    delete p;
    return 0;
};

// ❌ Not allowed: I/O
constexpr auto bad4 = []() {
    std::cout << "Hello";  // Error
    return 0;
};

Summary

Key Points

  1. C++17 constexpr lambda: Implicitly constexpr
  2. Compile-time calculation: No runtime cost
  3. Type checking: Powerful with type_traits
  4. Metaprogramming: Template + lambda combination
  5. Constraints: No I/O, dynamic allocation

When to Use

Use constexpr lambda when:

  • Need compile-time calculation
  • Metaprogramming
  • Type validation
  • Performance optimization

Don’t use when:

  • Need I/O operations
  • Dynamic allocation required
  • Too complex (readability matters)

Best Practices

  • ✅ Use for compile-time calculation
  • ✅ Combine with templates
  • ✅ Use for type checking
  • ❌ Don’t overuse (readability first)
  • ❌ Don’t use for side effects

Master compile-time programming with constexpr lambda! 🚀


Frequently Asked Questions (FAQ)

Q. When would I use this in practice?

A. Everything about C++ constexpr Lambda : from basic concepts to practical applications.

Q. What should I read before this?

A. Follow the previous article or related articles links at the bottom of each post to learn in sequence. See the C++ series index for the full picture.

Q. Where can I study this more deeply?

A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.


Other articles related to this topic.


Keywords Covered in This Article (Related Search Terms)

This article covers C++, lambda, constexpr, C++17, compile-time.