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

C++ constexpr if | 'Compile-Time Branching' Guide

C++ constexpr if | 'Compile-Time Branching' Guide

이 글의 핵심

C++17 if constexpr is a conditional statement evaluated only at compile-time within templates. Used with constexpr functions and constant initialization, can handle branching with type_traits in one function instead of template specialization.

Introduction

C++17 if constexpr is a conditional statement evaluated only at compile-time within templates. When branching with type_traits, can handle in one function instead of template specialization.

#include <iostream>
#include <type_traits>

// Template function: can accept any type T
template<typename T>
void process(T value) {
    // if constexpr: evaluate condition at compile-time
    // Only selected branch is generated as code (rest is removed)
    
    // std::is_integral_v<T>: check if T is integer type
    // (int, long, short, char, etc.)
    if constexpr (std::is_integral_v<T>) {
        std::cout << "Integer: " << value << std::endl;
    } 
    // std::is_floating_point_v<T>: check if T is floating-point type
    // (float, double, long double)
    else if constexpr (std::is_floating_point_v<T>) {
        std::cout << "Float: " << value << std::endl;
    } 
    // Other types (string, pointer, etc.)
    else {
        std::cout << "Other: " << value << std::endl;
    }
}

int main() {
    process(42);        // T=int → only first branch compiled
    process(3.14);      // T=double → only second branch compiled
    process("hello");   // T=const char* → only third branch compiled
}

Output:

Integer
Integer: 43
Other

1. Regular if vs constexpr if

Comparison Table

AspectRegular ifconstexpr if
Evaluation timeRuntimeCompile-time
ConditionRuntime valueCompile-time constant
Code generationAll branches generatedOnly selected branch
Type checkingAll branches checkedOnly selected branch
OptimizationCompiler-dependentGuaranteed
Usage locationAnywhereMainly templates

Code Generation Difference

#include <iostream>
#include <type_traits>

// Regular if: runtime evaluation
template<typename T>
void func1(T value) {
    // Regular if: evaluate condition at runtime
    // Problem: all branches must compile
    if (std::is_integral_v<T>) {  // Runtime
        // value++;  // ❌ Compile error!
        // If T is string, value++ is invalid code
        // Must compile even if not executed
        std::cout << "Integer" << std::endl;
    }
}

// constexpr if: compile-time evaluation
template<typename T>
void func2(T value) {
    // if constexpr: evaluate condition at compile-time
    // Only selected branch is compiled
    if constexpr (std::is_integral_v<T>) {  // Compile-time
        // Only this code compiled if T is integer
        value++;  // ✅ OK (this code itself removed if T is string)
        std::cout << "Integer: " << value << std::endl;
    } else {
        // Only this code compiled if T is not integer
        std::cout << "Not integer" << std::endl;
    }
}

int main() {
    func1(42);                   // Runtime branch
    func1(std::string("test"));  // Runtime branch
    
    func2(42);                   // Compile-time: only first branch generated
    func2(std::string("test"));  // Compile-time: only second branch generated
    
    return 0;
}

2. Replacing Template Specialization

Implementation Comparison

ItemTemplate Specializationconstexpr if
Lines of codeMany (function per type)Few (one function)
MaintenanceDifficultEasy
ReadabilityScatteredConcentrated
Compile timeSlowFast
DebuggingDifficultEasy
#include <iostream>
#include <type_traits>

// ❌ Template specialization (complex)
template<typename T>
void print(T value);

template<>
void print<int>(int value) {
    std::cout << "int: " << value << std::endl;
}

template<>
void print<double>(double value) {
    std::cout << "double: " << value << std::endl;
}

template<>
void print<const char*>(const char* value) {
    std::cout << "string: " << value << std::endl;
}

// ✅ constexpr if (simple)
template<typename T>
void printModern(T value) {
    if constexpr (std::is_same_v<T, int>) {
        std::cout << "int: " << value << std::endl;
    } else if constexpr (std::is_same_v<T, double>) {
        std::cout << "double: " << value << std::endl;
    } else if constexpr (std::is_same_v<T, const char*>) {
        std::cout << "string: " << value << std::endl;
    } else {
        std::cout << "other: " << value << std::endl;
    }
}

int main() {
    std::cout << "=== Template Specialization ===" << std::endl;
    print(42);
    print(3.14);
    print("hello");
    
    std::cout << "\n=== constexpr if ===" << std::endl;
    printModern(42);
    printModern(3.14);
    printModern("world");
    
    return 0;
}

Summary

Key Points

  1. if constexpr: C++17 compile-time conditional
  2. Code generation: Only selected branch generated
  3. Template simplification: Replaces template specialization
  4. Type traits: Powerful with type_traits
  5. Zero overhead: No runtime cost

When to Use

Use if constexpr when:

  • Template metaprogramming
  • Type-dependent branching
  • Replacing template specialization
  • Compile-time optimization

Don’t use when:

  • Regular runtime conditions
  • Non-template code
  • Simple cases (overkill)

Best Practices

  • ✅ Use with type_traits
  • ✅ Simplify template code
  • ✅ Reduce code duplication
  • ❌ Don’t overuse (readability matters)
  • ❌ Don’t use for runtime conditions

Master compile-time branching with if constexpr! 🚀


자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. C++17 if constexpr is a conditional statement evaluated only at compile-time within templates.

Q. 선행으로 읽으면 좋은 글은?

A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.


이 글에서 다루는 키워드 (관련 검색어)

C++, constexpr, if constexpr, compile-time, template 등으로 검색하시면 이 글이 도움이 됩니다.