[2026] C++ `if constexpr` | Compile-Time Branching in Templates (C++17)
이 글의 핵심
Use `if constexpr` to discard untaken branches during instantiation—unlike runtime `if`, avoiding ill-formed code in unused branches for templates.
What is if constexpr?
Compile-time branching for templates (C++17). Discarded branches are not instantiated. 아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
template<typename T>
auto getValue(T value) {
if constexpr (std::is_pointer_v<T>) {
return *value; // Only compiled when T is pointer
} else {
return value;
}
}
int x = 10;
auto a = getValue(x); // Uses else branch
auto b = getValue(&x); // Uses if branch
Basic usage
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <type_traits>
#include <iostream>
template<typename T>
void print(T value) {
if constexpr (std::is_integral_v<T>) {
std::cout << "Integer: " << value << "\n";
} else if constexpr (std::is_floating_point_v<T>) {
std::cout << "Float: " << value << "\n";
} else {
std::cout << "Other: " << value << "\n";
}
}
// Usage
print(42); // "Integer: 42"
print(3.14); // "Float: 3.14"
print("hello"); // "Other: hello"
if vs if constexpr
Runtime if: All branches must compile
아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
template<typename T>
void processRuntime(T value) {
if (std::is_pointer_v<T>) {
std::cout << *value; // ❌ Error when T=int: cannot dereference int
} else {
std::cout << value;
}
}
if constexpr: Only selected branch compiled
아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
template<typename T>
void processCompileTime(T value) {
if constexpr (std::is_pointer_v<T>) {
std::cout << *value; // ✅ OK: only compiled when T is pointer
} else {
std::cout << value;
}
}
Real-world examples
1. Generic serialization
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <type_traits>
#include <string>
#include <sstream>
template<typename T>
std::string toString(const T& value) {
if constexpr (std::is_arithmetic_v<T>) {
return std::to_string(value);
} else if constexpr (std::is_same_v<T, std::string>) {
return value;
} else if constexpr (std::is_same_v<T, const char*>) {
return std::string(value);
} else {
std::ostringstream oss;
oss << value;
return oss.str();
}
}
// Usage
auto s1 = toString(42); // "42"
auto s2 = toString(3.14); // "3.140000"
auto s3 = toString("hello"); // "hello"
2. Container optimization
다음은 cpp를 활용한 상세한 구현 코드입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
template<typename Container, typename T>
void addElement(Container& c, const T& value) {
// Reserve space if container supports it
if constexpr (requires { c.reserve(1); }) {
c.reserve(c.size() + 1);
}
// Use push_back if available, otherwise insert
if constexpr (requires { c.push_back(value); }) {
c.push_back(value);
} else {
c.insert(c.end(), value);
}
}
// Works with vector (has reserve + push_back)
std::vector<int> vec;
addElement(vec, 10);
// Works with set (has insert only)
std::set<int> s;
addElement(s, 10);
3. Variadic print with recursion
template<typename T>
void print(const T& value) {
std::cout << value << "\n";
}
template<typename T, typename....Rest>
void print(const T& first, const Rest&....rest) {
std::cout << first;
if constexpr (sizeof...(rest) > 0) {
std::cout << ", ";
print(rest...); // Recursive call
} else {
std::cout << "\n";
}
}
// Usage
print(1, 2, 3, "hello", 3.14);
// Output: 1, 2, 3, hello, 3.14
Replacing SFINAE
Before C++17: SFINAE with enable_if
아래 코드는 cpp를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// Overload 1: for integral types
template<typename T>
std::enable_if_t<std::is_integral_v<T>, T>
square(T x) {
return x * x;
}
// Overload 2: for floating-point types
template<typename T>
std::enable_if_t<std::is_floating_point_v<T>, T>
square(T x) {
return x * x;
}
After C++17: Single function with if constexpr
아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
template<typename T>
T square(T x) {
if constexpr (std::is_integral_v<T>) {
return x * x;
} else if constexpr (std::is_floating_point_v<T>) {
return x * x;
} else {
static_assert(std::is_arithmetic_v<T>, "T must be arithmetic");
}
}
Common mistakes
Mistake 1: Using runtime condition
아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
template<typename T>
void process(T value, bool flag) {
if constexpr (flag) { // ❌ Error: flag is not constant expression
// ...
}
}
// ✅ Fix: use runtime if
if (flag) {
// ...
}
Mistake 2: Expecting different return types
아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
template<typename T>
auto getValue(T x) {
if constexpr (std::is_pointer_v<T>) {
return *x; // Returns T's pointee type
} else {
return &x; // Returns T*
}
}
// ❌ Error: inconsistent return types
Fix: Use common return type or std::variant:
아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
template<typename T>
auto getValue(T x) -> std::conditional_t<std::is_pointer_v<T>,
std::remove_pointer_t<T>,
T> {
if constexpr (std::is_pointer_v<T>) {
return *x;
} else {
return x;
}
}
Mistake 3: Assuming complete elimination
아래 코드는 cpp를 사용한 구현 예제입니다. 에러 처리를 통해 안정성을 확보합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
template<typename T>
void debug(T value) {
if constexpr (false) {
value.nonExistentMethod(); // ⚠️ May still cause error in some contexts
}
}
Note: Discarded branches still undergo phase 1 parsing. They must be syntactically valid.
Performance implications
Zero runtime cost: if constexpr is resolved at compile time. Generated code contains only the selected branch.
Assembly comparison (GCC 13, -O3):
아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
template<typename T>
int process(T x) {
if constexpr (std::is_integral_v<T>) {
return x * 2;
} else {
return static_cast<int>(x);
}
}
int a = process(10); // Assembly: imul eax, 2
int b = process(3.14); // Assembly: cvttsd2si eax, xmm0
No branching instructions—completely different code paths.
Compiler support
| Compiler | if constexpr | Notes |
|---|---|---|
| GCC | 7+ | Full support |
| Clang | 3.9+ | Full support |
| MSVC | 2017 15.3+ | Full support |
Related posts
Keywords
C++, if constexpr, C++17, compile-time, templates, metaprogramming, SFINAE alternative