C++ if constexpr | "컴파일 타임 if" 가이드
이 글의 핵심
C++ if constexpr에 대한 실전 가이드입니다. 개념부터 실무 활용까지 예제와 함께 상세히 설명합니다.
if constexpr란?
컴파일 타임에 분기 결정 (C++17)
template<typename T>
auto getValue(T value) {
if constexpr (std::is_pointer_v<T>) {
return *value; // 포인터
} else {
return value; // 값
}
}
기본 사용
template<typename T>
void print(T value) {
if constexpr (std::is_integral_v<T>) {
std::cout << "정수: " << value << std::endl;
} else if constexpr (std::is_floating_point_v<T>) {
std::cout << "실수: " << value << std::endl;
} else {
std::cout << "기타: " << value << std::endl;
}
}
print(10); // "정수: 10"
print(3.14); // "실수: 3.14"
print("Hi"); // "기타: Hi"
실전 예시
예시 1: 타입별 처리
#include <type_traits>
#include <string>
template<typename T>
std::string toString(T value) {
if constexpr (std::is_same_v<T, bool>) {
return value ? "true" : "false";
} else if constexpr (std::is_arithmetic_v<T>) {
return std::to_string(value);
} else if constexpr (std::is_convertible_v<T, std::string>) {
return value;
} else {
return "unknown";
}
}
int main() {
std::cout << toString(true) << std::endl; // "true"
std::cout << toString(42) << std::endl; // "42"
std::cout << toString("Hello") << std::endl; // "Hello"
}
예시 2: 재귀 종료
template<typename T, typename... Rest>
void print(T first, Rest... rest) {
std::cout << first;
if constexpr (sizeof...(rest) > 0) {
std::cout << ", ";
print(rest...); // 재귀
} else {
std::cout << std::endl;
}
}
int main() {
print(1, 2, 3, 4, 5); // 1, 2, 3, 4, 5
}
예시 3: 최적화
template<typename T>
T multiply(T a, T b) {
if constexpr (std::is_integral_v<T>) {
// 정수: 비트 시프트 최적화
if (b == 2) return a << 1;
if (b == 4) return a << 2;
}
return a * b;
}
예시 4: SFINAE 대체
// ❌ SFINAE (복잡)
template<typename T>
std::enable_if_t<std::is_integral_v<T>, T>
process(T value) {
return value * 2;
}
// ✅ if constexpr (간단)
template<typename T>
auto process(T value) {
if constexpr (std::is_integral_v<T>) {
return value * 2;
} else {
return value;
}
}
if vs if constexpr
template<typename T>
void func(T value) {
// 런타임 if: 모든 분기 컴파일
if (std::is_integral_v<T>) {
// value.length(); // 에러: int에 없음
}
// 컴파일 타임 if: 선택된 분기만 컴파일
if constexpr (std::is_integral_v<T>) {
return value * 2;
} else {
return value.length(); // OK: 정수 아닐 때만
}
}
자주 발생하는 문제
문제 1: 비템플릿 함수
// ❌ 일반 함수에서 사용
void func(int x) {
if constexpr (x > 0) { // 에러: x는 런타임 값
// ...
}
}
// ✅ constexpr 값
constexpr int MAX = 100;
void func() {
if constexpr (MAX > 0) { // OK
// ...
}
}
문제 2: 모든 분기 문법 검사
template<typename T>
void func(T value) {
if constexpr (std::is_integral_v<T>) {
return value * 2;
} else {
return value.foo(); // 문법 검사됨
}
}
// func<int>(10); // 에러: int에 foo() 없음 (문법 검사)
문제 3: 중첩
template<typename T>
void func(T value) {
if constexpr (std::is_pointer_v<T>) {
if constexpr (std::is_const_v<std::remove_pointer_t<T>>) {
// const 포인터
} else {
// 비const 포인터
}
}
}
문제 4: 반환 타입
template<typename T>
auto func(T value) {
if constexpr (std::is_integral_v<T>) {
return value * 2; // int
} else {
return value * 2.0; // double
}
}
// 반환 타입이 T에 따라 다름
활용 패턴
// 1. 타입 변환
template<typename T>
auto convert(T value) {
if constexpr (std::is_same_v<T, std::string>) {
return value;
} else {
return std::to_string(value);
}
}
// 2. 컨테이너 처리
template<typename Container>
void process(Container& c) {
if constexpr (requires { c.reserve(10); }) {
c.reserve(100); // vector, string
}
}
// 3. 최적화
template<size_t N>
void func() {
if constexpr (N < 10) {
// 작은 N: 간단한 구현
} else {
// 큰 N: 최적화된 구현
}
}
FAQ
Q1: if constexpr는 언제?
A: C++17. 컴파일 타임 분기.
Q2: if와 차이?
A:
- if: 런타임, 모든 분기 컴파일
- if constexpr: 컴파일 타임, 선택된 분기만
Q3: 성능?
A: 런타임 비용 없음.
Q4: SFINAE 대체?
A: 가능. 더 간단함.
Q5: 비템플릿 함수?
A: constexpr 값만 사용 가능.
Q6: if constexpr 학습 리소스는?
A:
- “C++17 The Complete Guide”
- “Effective Modern C++”
- cppreference.com
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- C++ constexpr Lambda | “컴파일 타임 람다” 가이드
- C++ CTAD | “클래스 템플릿 인자 추론” 가이드
- C++ constexpr 함수 | “컴파일 타임 함수” 가이드
관련 글
- C++ CTAD |
- C++ constexpr Lambda |
- C++ Deduction Guides |
- C++ any |
- C++ auto 타입 추론 | 복잡한 타입을 컴파일러에 맡기기