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이면 해당 코드 자체가 제거됨
템플릿 프로그래밍 활용 타입에 따라 최적화된 코드 생성 가능
실행 성능 향상 실행 시 조건 검사 불필요 → 최적화 효과