[C++23 새기능 소개] if consteval

C++23에서는 함수 내에서 해당 코드가 컴파일 타임 상수 표현식으로 평가되고 있는지 확인할 수 있는 새로운 흐름 제어 문법인 if consteval이 도입되었습니다. 이번 글에서는 if consteval의 개념과 사용법, 그리고 이전 버전과 비교하여 어떻게 개선되었는지 알아보겠습니다.

if consteval이란 무엇인가요?

if consteval은 함수 내부에서 현재 함수 호출이 컴파일 타임 상수 표현식(constexpr context)으로 평가되는지 여부를 검사하는 문법입니다. 이를 통해 코드를 컴파일 타임과 런타임 상황에 따라 다르게 처리할 수 있습니다. 예를 들어, 런타임에서는 허용되는 동작이지만 컴파일 타임에는 허용되지 않는 로직을 분기할 수 있습니다.

이전 버전에서는 어떻게 했나요?

C++20까지는 함수가 컴파일 타임 상수 표현식으로 평가 중인지 명확하게 판별하기 어려웠습니다. constexpr 함수를 사용해도, 해당 함수가 컴파일 타임 상수 표현식으로 사용되는지 런타임에 사용되는지는 컨텍스트에 따라 달랐으며, 이를 동적으로 확인하기 위한 직접적인 문법은 존재하지 않았습니다.

예제: 기존 방식

constexpr int square(int x) {
    return x * x;
}

int main() {
    constexpr int val = square(5);  // 컴파일 타임 상수 표현식
    int runtime_val = 5;
    int result = square(runtime_val); // 런타임 연산
}
  • 위 예제에서는 square 함수가 constexpr 함수이지만, val을 초기화할 때는 컴파일 타임 상수 표현식으로 사용되고, result를 계산할 때는 런타임 값이므로 런타임 평가가 이루어집니다.
  • 그러나 함수 내부에서 "지금 이 호출이 컴파일 타임 상수 평가 중인지"를 판별하는 것은 불가능했습니다.

C++23의 if consteval을 사용한 개선

if consteval을 사용하면 함수 내에서 현재 호출이 컴파일 타임 상수 표현식 평가인지 확인한 뒤, 그에 따라 다른 코드를 실행할 수 있습니다.

예제: if consteval 사용

#include <iostream>

constexpr int computeValue(int x) {
    if consteval {
        // 컴파일 타임 상수 표현식 평가 중이라면 이 부분 실행
        return x * x; 
    } else {
        // 런타임 평가 중이라면 이 부분 실행
        std::cout << "런타임 평가 중입니다.\n";
        return x * 2;
    }
}

int main() {
    constexpr int compileTimeVal = computeValue(5);  // 컴파일 타임 평가: 결과 = 25
    int runtimeVal = 10;
    int runRes = computeValue(runtimeVal);           // 런타임 평가: 결과 = 20

    std::cout << "compileTimeVal: " << compileTimeVal << "\n"; // 25
    std::cout << "runRes: " << runRes << "\n";                 // 20

    return 0;
}
  • if consteval을 사용하면 컴파일러는 compileTimeVal 계산 시 컴파일 타임 분기 부분을 사용하고, runRes 계산 시 런타임 분기 부분을 사용합니다.
  • 이를 통해 동일한 함수 내에서 컴파일 타임 평가와 런타임 평가를 구분할 수 있습니다.

어떻게 좋아졌나요?

  • 명확한 분기: 이전에는 컨텍스트에 따라 함수를 호출하는 방식으로만 컴파일 타임/런타임을 구분했다면, 이제는 함수 내부에서 명시적으로 분기할 수 있습니다.
  • 코드 품질 향상: 특정 로직이 컴파일 타임 상수 표현식일 때만 유효한 연산을 수행하거나, 런타임일 때만 필요한 부수적 동작(로그 출력, 동적 할당 등)을 수행하는 등의 미세 조정이 가능합니다.
  • 오류 방지: 컴파일 타임에만 유효한 API 호출을 런타임에 사용하지 않도록 하는 등 안전성을 높일 수 있습니다.

상세한 예제와 비교

1. 콘솔 출력 제어

기존 방식

constexpr int doWork(int x) {
    // 컴파일 타임에 평가 중이면 출력 불가(런타임 함수 호출 불가)
    // 하지만 이를 함수 내부에서 구분할 수 없음
    return x * x;
}

C++23 방식

constexpr int doWork(int x) {
    if consteval {
        // 컴파일 타임 상수 표현식 평가 중
        return x * x;
    } else {
        // 런타임 평가 중
        std::cout << "런타임에서만 수행되는 동작\n";
        return x * 2;
    }
}
  • 이제 함수 내부에서 출력(런타임 전용)을 안전하게 분기하여 처리할 수 있습니다.

2. 특수한 연산 제한

constexpr int safeCompute(int x) {
    if consteval {
        // 컴파일 타임에서만 허용되는 특별한 최적화나 상수 연산 수행
        return x * x * x;
    } else {
        // 런타임에서는 다른 로직 수행
        return x + x;
    }
}
  • 컴파일 타임 컨텍스트에서만 유효한 연산을 안전하게 명시할 수 있습니다.

주의 사항

  • 컴파일러 지원: if consteval은 C++23 기능이므로, 이를 지원하는 컴파일러와 표준 라이브러리가 필요합니다.
  • 적절한 사용 사례 선택: 모든 함수에서 if consteval을 사용하는 것은 비효율적일 수 있습니다. 컴파일 타임과 런타임 동작을 명확히 구분해야 할 때 적합합니다.
  • 런타임 전용 동작 주의: if consteval 블록 안에서는 런타임에서 허용되지 않는 동작을 하지 않도록 주의해야 합니다.

요약

C++23의 if consteval은 함수 내부에서 현재 호출이 컴파일 타임 상수 표현식 평가인지 런타임 평가인지 명확하게 구분할 수 있는 기능을 제공합니다. 이전에는 이러한 구분을 컨텍스트에 맡기거나 복잡한 템플릿 메타프로그래밍으로 우회해야 했지만, 이제는 간단한 분기문을 통해 코드 품질과 안전성을 향상시킬 수 있습니다.

 

 

참고 자료:

반응형