C++ 초급 - 3. 제어문 (3 - if constexpr (C++17, Compile-Time If Statement))
2025. 2. 12. 16:46ㆍ프로그래밍 언어/C++
📌 3.3 if constexpr (C++17, Compile-Time If Statement)
if constexpr 문은 C++17에서 도입된 컴파일 타임 조건문으로,
컴파일 시간에 조건을 평가하여 불필요한 코드를 제거하는 최적화 기법이다.
이 기능은 특히 템플릿 프로그래밍에서 유용하게 사용되며,
일반적인 if 문과 달리 실행 시 조건을 평가하지 않고, 컴파일 타임에서 분기 처리를 결정한다.
📌 1. if constexpr의 기본 개념
🔹 if constexpr vs 일반 if
구분 | if 문 | if constexpr 문 |
조건 평가 시점 | 실행 시간(Runtime) | 컴파일 시간(Compile-Time) |
분기 방식 | 실행 중 조건을 검사하고 분기 | 불필요한 코드가 제거됨 |
성능 | 실행 시 조건 체크 필요 | 불필요한 분기 코드가 제거됨 → 최적화 |
활용 | 일반적인 조건문에 사용 | 템플릿 프로그래밍, 타입 기반 분기 |
📌 if constexpr 기본 구조
if constexpr (컴파일 시간에 평가 가능한 조건) {
// 조건이 참이면 이 블록의 코드가 컴파일됨
} else {
// 조건이 거짓이면 이 블록의 코드가 컴파일됨
}
📌 2. if constexpr vs 일반 if 비교 예제
🔹 일반 if 문 예제
#include <iostream>
void checkNumber(int num) {
if (num % 2 == 0) {
std::cout << "짝수입니다." << std::endl;
} else {
std::cout << "홀수입니다." << std::endl;
}
}
int main() {
checkNumber(10);
return 0;
}
🔹 출력 결과
짝수입니다.
💡 일반 if 문은 실행 시간에 조건을 평가하고, num % 2 == 0 여부를 검사한 후 분기한다.
🔹 if constexpr을 사용한 예제
#include <iostream>
template <typename T>
void checkType() {
if constexpr (std::is_integral<T>::value) {
std::cout << "정수형 타입입니다." << std::endl;
} else {
std::cout << "실수형 타입입니다." << std::endl;
}
}
int main() {
checkType<int>(); // 정수형
checkType<double>(); // 실수형
return 0;
}
🔹 출력 결과
정수형 타입입니다.
실수형 타입입니다.
💡 설명
- std::is_integral<T>::value는 T가 정수형인지 확인하는 컴파일 타임 조건이다.
- 컴파일 시 if constexpr 조건이 평가되므로, 불필요한 코드가 제거된다.
- 템플릿 특수화 없이도 타입에 따라 최적화된 코드가 생성됨.
📌 3. if constexpr을 활용한 최적화 사례
🔹 1. 정적 배열 크기 검사
if constexpr을 사용하여 컴파일 타임에 배열 크기를 검사할 수 있다.
#include <iostream>
template <typename T, std::size_t N>
void checkArraySize(const T (&arr)[N]) {
if constexpr (N > 5) {
std::cout << "배열 크기가 5보다 큽니다." << std::endl;
} else {
std::cout << "배열 크기가 5 이하입니다." << std::endl;
}
}
int main() {
int arr1[3] = {1, 2, 3};
int arr2[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
checkArraySize(arr1); // 크기 5 이하
checkArraySize(arr2); // 크기 5 이상
return 0;
}
🔹 출력 결과
배열 크기가 5 이하입니다.
배열 크기가 5보다 큽니다.
💡 컴파일 시점에서 N > 5 여부가 평가되므로, 조건문이 최적화됨.
🔹 2. 타입에 따라 다른 코드 실행
템플릿 프로그래밍에서 타입에 따라 다른 연산을 수행할 때 if constexpr을 활용할 수 있다.
#include <iostream>
#include <type_traits>
template <typename T>
void processValue(T value) {
if constexpr (std::is_integral<T>::value) {
std::cout << "정수 연산 수행: " << value * 2 << std::endl;
} else {
std::cout << "실수 연산 수행: " << value / 2 << std::endl;
}
}
int main() {
processValue(10); // 정수 → 두 배
processValue(3.14); // 실수 → 반으로 나누기
return 0;
}
🔹 출력 결과
정수 연산 수행: 20
실수 연산 수행: 1.57
💡 템플릿을 사용할 때, 타입에 따라 다른 연산을 수행하도록 최적화할 수 있다.
🔹 3. if constexpr과 constexpr 함수 결합
if constexpr과 constexpr 함수를 결합하면 컴파일 타임에 최적화된 연산을 수행할 수 있다.
#include <iostream>
constexpr int factorial(int n) {
return (n <= 1) ? 1 : (n * factorial(n - 1));
}
template <int N>
void printFactorial() {
if constexpr (N >= 0) {
std::cout << N << "! = " << factorial(N) << std::endl;
} else {
std::cout << "음수 팩토리얼은 계산할 수 없습니다." << std::endl;
}
}
int main() {
printFactorial<5>();
printFactorial<-1>(); // 음수 예외 처리
return 0;
}
🔹 출력 결과
5! = 120
음수 팩토리얼은 계산할 수 없습니다.
💡 컴파일 타임에서 N 값이 평가되므로, 음수일 경우 불필요한 연산이 제거된다.
📌 4. if constexpr 사용 시 주의할 점
🔹 1. 반드시 컴파일 타임에서 평가될 수 있는 조건 사용
- if constexpr 조건은 컴파일 타임에서 평가 가능해야 한다.
- 실행 시간에서만 결정되는 조건은 사용 불가능.
int x;
std::cin >> x;
if constexpr (x > 10) { // ❌ 오류: 실행 시간 변수는 사용할 수 없음
std::cout << "10보다 큽니다.";
}
🔹 컴파일 오류 발생!
error: the value of 'x' is not usable in a constant expression
💡 해결 방법: if 문을 사용해야 함.
📌 5. if constexpr vs template specialization (템플릿 특수화)
과거에는 if constexpr 없이 템플릿 특수화를 사용해야 했음.
template <typename T>
struct TypeChecker {
static void check() { std::cout << "일반 타입" << std::endl; }
};
template <>
struct TypeChecker<int> {
static void check() { std::cout << "정수 타입" << std::endl; }
};
💡 if constexpr을 사용하면 템플릿 특수화 없이도 같은 기능을 구현 가능!
📌 정리
특징 | 설명 |
컴파일 타임 평가 | 실행 시가 아니라 컴파일 시에 조건을 평가 |
불필요한 코드 제거 | 조건이 false이면 해당 코드 자체가 제거됨 |
템플릿 프로그래밍 활용 | 타입에 따라 최적화된 코드 생성 가능 |
실행 성능 향상 | 실행 시 조건 검사 불필요 → 최적화 효과 |