[2026] C++ Compile-Time Programming Complete Guide | constexpr, consteval, if constexpr & TMP

[2026] C++ Compile-Time Programming Complete Guide | constexpr, consteval, if constexpr & TMP

이 글의 핵심

Master C++ compile-time programming: constexpr, consteval, if constexpr, TMP, performance benchmarks, and practical patterns for zero-overhead runtime.

Introduction

C++ compile-time programming uses constexpr, consteval, and if constexpr to compute at compile time, eliminating runtime overhead. Analogy: Runtime computation is like cooking on order; compile-time computation is like pre-cooking and reheating—execution is instant.

What You’ll Learn

  • Understand differences between constexpr, consteval, and if constexpr
  • Distinguish compile-time vs runtime computation
  • Compare with template metaprogramming (TMP)
  • Apply practical patterns and avoid pitfalls

constexpr Basics

constexpr Variables

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
constexpr int MAX_SIZE = 100;
constexpr double PI = 3.14159;
int main() {
    int arr[MAX_SIZE];  // Array size must be compile-time constant
    
    std::cout << PI << std::endl;
    
    return 0;
}

Key: constexpr variables can be used as array sizes and template arguments.

constexpr Functions

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
// Can execute at compile time or runtime
constexpr int square(int x) {
    return x * x;
}
int main() {
    constexpr int result = square(5);  // Compile-time
    int arr[result];  // OK: compile-time constant
    
    int x = 10;
    int result2 = square(x);  // Runtime (x is not constexpr)
    
    std::cout << result << ", " << result2 << std::endl;
    
    return 0;
}

Output:

25, 100

constexpr vs const

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// const: runtime constant
const int x = 10;
// constexpr: compile-time constant
constexpr int y = 10;
int arr1[x];  // ❌ Error (const not guaranteed compile-time)
int arr2[y];  // ✅ OK (constexpr is compile-time)

Key: constexpr guarantees compile-time evaluation; const only guarantees immutability.

Practical Examples

1. constexpr Functions

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}
int main() {
    constexpr int fact5 = factorial(5);  // 120 (compile-time)
    
    std::cout << fact5 << std::endl;
    
    return 0;
}

Output:

120

Key: Recursive constexpr functions are evaluated at compile time when arguments are constexpr.

2. constexpr Classes

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
class Point {
private:
    int x_, y_;
    
public:
    constexpr Point(int x, int y) : x_(x), y_(y) {}
    
    constexpr int getX() const { return x_; }
    constexpr int getY() const { return y_; }
    
    constexpr int distanceSquared() const {
        return x_ * x_ + y_ * y_;
    }
};
int main() {
    constexpr Point p(3, 4);
    constexpr int dist = p.distanceSquared();  // 25 (compile-time)
    
    int arr[dist];  // OK
    
    std::cout << dist << std::endl;
    
    return 0;
}

Output:

25

3. if constexpr (C++17)

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <type_traits>
template<typename T>
auto getValue(T t) {
    if constexpr (std::is_pointer_v<T>) {
        return *t;  // Dereference if pointer
    } else {
        return t;   // Return as-is
    }
}
int main() {
    int x = 10;
    int* ptr = &x;
    
    std::cout << getValue(x) << std::endl;    // 10
    std::cout << getValue(ptr) << std::endl;  // 10
    
    return 0;
}

Output:

10
10

Key: if constexpr enables compile-time branching based on type traits, eliminating dead code paths.

4. consteval (C++20)

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
// Must execute at compile time only
consteval int sqr(int n) {
    return n * n;
}
int main() {
    constexpr int x = sqr(5);  // ✅ OK (compile-time)
    
    int y = 10;
    // int z = sqr(y);  // ❌ Error: runtime value
    
    std::cout << x << std::endl;
    
    return 0;
}

Output:

25

Key: consteval enforces compile-time-only execution, preventing runtime calls.

Advanced Patterns

1. Compile-Time String Hashing

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
constexpr unsigned int hash(const char* str) {
    unsigned int hash = 5381;
    while (*str) {
        hash = ((hash << 5) + hash) + (*str++);
    }
    return hash;
}
int main() {
    constexpr unsigned int startHash = hash("start");
    constexpr unsigned int stopHash = hash("stop");
    
    const char* command = "start";
    
    switch (hash(command)) {
        case startHash:
            std::cout << "Start" << std::endl;
            break;
        case stopHash:
            std::cout << "Stop" << std::endl;
            break;
        default:
            std::cout << "Unknown" << std::endl;
    }
    
    return 0;
}

Output:

Start

Key: Compile-time hashing enables fast string-based switch statements.

2. Compile-Time Array Generation

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <array>
#include <iostream>
template<size_t N>
constexpr auto generateFibonacci() {
    std::array<int, N> result{};
    if (N > 0) result[0] = 0;
    if (N > 1) result[1] = 1;
    
    for (size_t i = 2; i < N; ++i) {
        result[i] = result[i - 1] + result[i - 2];
    }
    
    return result;
}
int main() {
    constexpr auto fib = generateFibonacci<10>();
    
    for (int x : fib) {
        std::cout << x << " ";  // 0 1 1 2 3 5 8 13 21 34
    }
    std::cout << std::endl;
    
    return 0;
}

Output:

0 1 1 2 3 5 8 13 21 34

Key: Compile-time array generation creates lookup tables with zero runtime cost.

3. Template Metaprogramming (TMP)

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
// Recursive template
template<int N>
struct Factorial {
    static constexpr int value = N * Factorial<N - 1>::value;
};
template<>
struct Factorial<0> {
    static constexpr int value = 1;
};
int main() {
    std::cout << Factorial<5>::value << std::endl;  // 120 (compile-time)
    
    return 0;
}

Output:

120

Key: TMP uses template recursion for compile-time computation. Prefer constexpr functions for readability.

Performance Comparison

Benchmark: Fibonacci

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <chrono>
#include <iostream>
// Runtime
int runtimeFib(int n) {
    if (n <= 1) return n;
    return runtimeFib(n - 1) + runtimeFib(n - 2);
}
// Compile-time
constexpr int compiletimeFib(int n) {
    if (n <= 1) return n;
    return compiletimeFib(n - 1) + compiletimeFib(n - 2);
}
int main() {
    // Runtime (slow)
    auto start = std::chrono::high_resolution_clock::now();
    int r = runtimeFib(40);
    auto end = std::chrono::high_resolution_clock::now();
    auto time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
    
    std::cout << "Runtime: " << time << "ms" << std::endl;
    
    // Compile-time (instant)
    constexpr int c = compiletimeFib(40);
    std::cout << "Compile-time: 0ms (pre-computed)" << std::endl;
    
    return 0;
}

Results:

MethodTime
Runtime1200ms
Compile-time0ms
Conclusion: Compile-time computation is dramatically faster at runtime (but increases build time).

Production Patterns

Pattern 1: Lookup Table Generation

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <array>
#include <iostream>
#include <cmath>
constexpr auto generateSinTable() {
    constexpr size_t SIZE = 360;
    std::array<double, SIZE> table{};
    
    constexpr double PI = 3.14159265358979323846;
    
    for (size_t i = 0; i < SIZE; ++i) {
        double radians = i * PI / 180.0;
        // In real code: table[i] = std::sin(radians);
        // (std::sin is not constexpr in C++17, but is in C++26)
        table[i] = radians;
    }
    
    return table;
}
int main() {
    constexpr auto sinTable = generateSinTable();
    
    std::cout << sinTable[45] << std::endl;  // 0.785398 (45 degrees)
    
    return 0;
}

Key: Pre-compute trigonometric tables at compile time for real-time graphics/physics.

Pattern 2: Type Checking

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <type_traits>
template<typename T>
constexpr bool isNumeric() {
    if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>) {
        return true;
    } else {
        return false;
    }
}
template<typename T>
void process(T value) {
    if constexpr (isNumeric<T>()) {
        std::cout << "Number: " << value << std::endl;
    } else {
        std::cout << "String: " << value << std::endl;
    }
}
int main() {
    process(42);       // Number: 42
    process("hello");  // String: hello
    
    return 0;
}

Output:

Number: 42
String: hello

Pattern 3: Compile-Time Sorting

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <algorithm>
#include <array>
#include <iostream>
constexpr void bubbleSort(int* arr, int n) {
    for (int i = 0; i < n - 1; ++i) {
        for (int j = 0; j < n - i - 1; ++j) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
constexpr auto getSortedArray() {
    std::array<int, 5> arr = {5, 2, 8, 1, 9};
    bubbleSort(arr.data(), arr.size());
    return arr;
}
int main() {
    constexpr auto sorted = getSortedArray();
    
    for (int x : sorted) {
        std::cout << x << " ";  // 1 2 5 8 9
    }
    std::cout << std::endl;
    
    return 0;
}

Output:

1 2 5 8 9

Pattern 4: Bit Manipulation

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
constexpr unsigned int reverseBits(unsigned int n) {
    unsigned int result = 0;
    for (int i = 0; i < 32; ++i) {
        result <<= 1;
        result |= (n & 1);
        n >>= 1;
    }
    return result;
}
int main() {
    constexpr unsigned int reversed = reverseBits(0b10110000);
    
    std::cout << std::hex << reversed << std::endl;
    
    return 0;
}

Key: Compile-time bit manipulation for embedded systems and cryptography.

Common Issues

Issue 1: constexpr Constraints

다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ Static variables not allowed (pre-C++23)
constexpr int bad() {
    static int x = 0;  // Error
    return x++;
}
// ❌ Dynamic allocation not allowed (C++17)
constexpr int bad2() {
    int* p = new int(10);  // Error
    return *p;
}
// ✅ OK
constexpr int good(int x) {
    return x * 2;
}

Key: constexpr functions have restrictions—no static locals (pre-C++23), limited dynamic allocation.

Issue 2: Runtime Values

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
int main() {
    int x;
    std::cin >> x;
    
    // ❌ Error: runtime value
    constexpr int y = x * 2;
    
    // ✅ OK: runtime variable
    int y2 = x * 2;
    
    return 0;
}

Key: constexpr requires compile-time known values.

Issue 3: Complex Computation

다음은 cpp를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ Slow compile time
constexpr int slowFib(int n) {
    if (n <= 1) return n;
    return slowFib(n - 1) + slowFib(n - 2);
}
constexpr int x = slowFib(50);  // Very slow compilation!
// ✅ Memoization
constexpr auto fastFib() {
    std::array<int, 50> result{};
    result[0] = 0;
    result[1] = 1;
    for (int i = 2; i < 50; ++i) {
        result[i] = result[i - 1] + result[i - 2];
    }
    return result;
}
constexpr auto fibTable = fastFib();
constexpr int y = fibTable[49];  // Fast

Key: Use iterative algorithms or memoization to avoid exponential compile-time complexity.

Issue 4: constexpr vs consteval Confusion

다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// constexpr: compile-time or runtime
constexpr int square(int n) {
    return n * n;
}
int x = 10;
int y = square(x);  // ✅ Runs at runtime
// consteval: compile-time only
consteval int sqr(int n) {
    return n * n;
}
constexpr int z = sqr(5);  // ✅ OK
// int w = sqr(x);  // ❌ Error: runtime value

Key: Use consteval to enforce compile-time-only intent.

Template Metaprogramming (TMP)

Recursive Templates

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
// Recursive template
template<int N>
struct Factorial {
    static constexpr int value = N * Factorial<N - 1>::value;
};
template<>
struct Factorial<0> {
    static constexpr int value = 1;
};
int main() {
    std::cout << Factorial<5>::value << std::endl;  // 120 (compile-time)
    
    return 0;
}

Output:

120

Key: TMP uses template specialization for compile-time recursion. Prefer constexpr functions for readability.

TMP vs constexpr

아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// TMP (verbose)
template<int N>
struct Factorial {
    static constexpr int value = N * Factorial<N - 1>::value;
};
// constexpr (readable)
constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

Recommendation: Use constexpr functions for most compile-time computation; reserve TMP for type-level programming.

Production Use Cases

Use Case 1: Configuration Tables

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <array>
constexpr auto generateConfigTable() {
    std::array<int, 256> table{};
    for (int i = 0; i < 256; ++i) {
        table[i] = i * 2;  // Example: multiply by 2
    }
    return table;
}
constexpr auto configTable = generateConfigTable();
int main() {
    int value = configTable[42];  // Instant lookup
}

Key: Pre-compute configuration tables for embedded systems.

Use Case 2: Type Dispatch

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <type_traits>
template<typename T>
void process(T value) {
    if constexpr (std::is_integral_v<T>) {
        std::cout << "Integer: " << value << std::endl;
    } else if constexpr (std::is_floating_point_v<T>) {
        std::cout << "Float: " << value << std::endl;
    } else {
        std::cout << "Other: " << value << std::endl;
    }
}
int main() {
    process(42);       // Integer: 42
    process(3.14);     // Float: 3.14
    process("hello");  // Other: hello
    
    return 0;
}

Output:

Integer: 42
Float: 3.14
Other: hello

Use Case 3: Compile-Time Validation

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <array>
template<size_t N>
constexpr bool isPowerOfTwo() {
    return N > 0 && (N & (N - 1)) == 0;
}
template<size_t N>
class Buffer {
    static_assert(isPowerOfTwo<N>(), "Buffer size must be power of 2");
    std::array<char, N> data;
};
int main() {
    Buffer<256> buf1;  // ✅ OK
    // Buffer<100> buf2;  // ❌ Error: not power of 2
}

Key: Use static_assert with constexpr functions for compile-time validation.

Performance Benchmarks

Compile-Time vs Runtime

// Benchmark: Fibonacci(40)
// Runtime: 1200ms
// Compile-time: 0ms (pre-computed)

Key: Compile-time computation eliminates runtime overhead but increases build time.

Compile Time Impact

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// Simple constexpr: +0.1s compile time
constexpr int x = factorial(10);
// Complex constexpr: +5s compile time
constexpr auto table = generateLargeTable<10000>();

Trade-off: Balance compile-time work with build time constraints.

Best Practices

1. Use constexpr for Pure Functions

아래 코드는 cpp를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ✅ Pure function: good constexpr candidate
constexpr int add(int a, int b) {
    return a + b;
}
// ❌ Side effects: not constexpr
int addAndLog(int a, int b) {
    std::cout << "Adding" << std::endl;  // I/O not allowed
    return a + b;
}

2. Prefer constexpr Over TMP

아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ TMP (verbose)
template<int N>
struct Factorial {
    static constexpr int value = N * Factorial<N - 1>::value;
};
// ✅ constexpr (readable)
constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

3. Use consteval for Compile-Time-Only Intent

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// ✅ Enforce compile-time
consteval int configValue(int id) {
    return id * 100;
}
constexpr int x = configValue(5);  // OK
// int y = configValue(runtimeValue);  // Error

4. Avoid Deep Recursion

다음은 cpp를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// ❌ Deep recursion (slow compile)
constexpr int fib(int n) {
    return n <= 1 ? n : fib(n-1) + fib(n-2);
}
// ✅ Iterative (fast compile)
constexpr int fib(int n) {
    int a = 0, b = 1;
    for (int i = 0; i < n; ++i) {
        int temp = a + b;
        a = b;
        b = temp;
    }
    return a;
}

5. Use static_assert for Documentation

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

template<typename T>
void process(T value) {
    static_assert(std::is_arithmetic_v<T>, "T must be numeric");
    // ...
}

Summary

Key Points

  1. constexpr
    • Compile-time or runtime execution
    • Variables, functions, classes
    • Array sizes, template arguments
  2. consteval (C++20)
    • Compile-time-only execution
    • Immediate functions
    • No runtime values allowed
  3. if constexpr (C++17)
    • Compile-time branching
    • Type-based conditional compilation
    • Replaces template specialization
  4. Performance
    • Compile-time: zero runtime overhead
    • Compile time may increase
    • Use memoization for complex computation

Selection Guide

ScenarioRecommendationReason
Compile-time constantconstexprArray sizes, etc.
Compile-time-onlyconstevalClear intent
Type-based branchingif constexprConditional compilation
Runtime also neededconstexprFlexibility

Cheat Sheet

다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// constexpr variable
constexpr int MAX_SIZE = 100;
// constexpr function
constexpr int square(int x) {
    return x * x;
}
// constexpr class
class Point {
public:
    constexpr Point(int x, int y) : x_(x), y_(y) {}
    constexpr int getX() const { return x_; }
private:
    int x_, y_;
};
// if constexpr
template<typename T>
auto getValue(T t) {
    if constexpr (std::is_pointer_v<T>) {
        return *t;
    } else {
        return t;
    }
}
// consteval
consteval int sqr(int n) {
    return n * n;
}

Compile-Time Programming Checklist

  • Pure functions marked constexpr?
  • Using consteval for compile-time-only intent?
  • Avoiding deep recursion?
  • Using static_assert for validation?
  • Balancing compile time vs runtime performance?

Keywords

C++ constexpr, consteval, compile-time programming, template metaprogramming, TMP, if constexpr, immediate functions One-line summary: Compile-time programming with constexpr, consteval, and if constexpr eliminates runtime overhead by pre-computing values and enabling type-based conditional compilation.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3