Namespaces
Variants

Constant expressions

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

컴파일 타임에 평가될 수 있는 expression 을 정의합니다.

이러한 표현식은 상수 템플릿 인수, 배열 크기 및 기타 상수 표현식이 필요한 상황에서 사용할 수 있습니다, 예를 들어

int n = 1;
std::array<int, n> a1;  // 오류: "n"은 상수 표현식이 아닙니다
const int cn = 2;
std::array<int, cn> a2; // 정상: "cn"은 상수 표현식입니다

목차

정의

아래에 나열된 상수 표현식 범주에 속하는 표현식은 상수 표현식 입니다.

C++98 상수 표현식 범주

정수 상수 표현식 (C++98)

다음 위치에서 C++는 정수나 열거형 상수로 평가되는 표현식을 요구합니다:

다음 모든 조건을 만족하는 표현식은 정수 상수 표현식 입니다:

  • 다음 개체들만 포함합니다:
  • 산술 타입의 리터럴
  • 열거자
  • 다음 모든 조건을 만족하는 변수나 정적 데이터 멤버:
  • const 한정자를 가짐
  • volatile 한정자를 가지지 않음
  • 정수 또는 열거형 타입임
  • 상수 표현식으로 초기화됨
  • 부동소수점 리터럴을 사용하지 않음 (단, 정수나 열거형 타입으로 명시적으로 변환 된 경우는 예외)
  • 비정수 및 비열거형 타입으로의 변환을 적용하지 않음
  • 다음 개체들을 sizeof 의 피연산자로만 사용하고 그 외에는 사용하지 않음:
  • 함수
  • 클래스 객체
  • 포인터
  • 참조
  • 대입 연산자
  • 증가 연산자
  • 감소 연산자
  • 함수 호출 연산자
  • 쉼표 연산자

기타 상수 표현식 범주

다른 표현식들은 상수 초기화 목적으로만 상수 표현식으로 간주됩니다. 이러한 상수 표현식은 다음 중 하나여야 합니다:

  • 널 포인터 값 으로 평가되는 표현식
  • 널 멤버 포인터 값으로 평가되는 표현식
  • 산술 상수 표현식
  • 주소 상수 표현식
  • 참조 상수 표현식
  • 완전 객체 타입에 대한 주소 상수 표현식에 정수 상수 표현식을 더하거나 뺀 표현식
  • 멤버 포인터 상수 표현식

산술 상수 표현식 은 정수 상수 표현식의 요구사항을 만족하는 표현식이지만 다음 예외가 적용됩니다:

  • 부동소수점 리터럴을 명시적 변환 없이 사용할 수 있음
  • 부동소수점 타입으로의 변환을 적용할 수 있음

주소 상수 표현식 은 다음 모든 조건을 만족하는 포인터 타입의 표현식입니다:

  • 주소 연산자를 명시적으로 사용
  • 포인터 타입의 상수 템플릿 매개변수를 암시적으로 사용
  • 배열 또는 함수 타입의 표현식 사용
  • 표현식이 어떤 함수도 호출하지 않음
  • 표현식이 명시적 포인터 변환 ( dynamic_cast 제외)과 다음 연산자를 결과 객체에 접근하지 않고 사용함:
  • 첨자 연산자
  • 간접 참조 연산자
  • 주소 연산자
  • 멤버 접근 연산자
  • 첨자 연산자를 사용하는 경우, 피연산자 중 하나가 정수 상수 표현식임

참조 상수 표현식 은 다음 모든 조건을 만족하는 참조 타입의 표현식입니다:

  • 참조가 정적 저장 기간을 가진 객체, 참조 타입의 상수 템플릿 매개변수, 또는 함수를 지정함. 참조는 비-POD 클래스 타입의 멤버나 기본 클래스를 지정하지 않음.
  • 표현식이 어떤 함수도 호출하지 않음
  • 표현식이 명시적 참조 변환 ( dynamic_cast 제외)과 다음 연산자를 결과 객체에 접근하지 않고 사용함:
  • 첨자 연산자
  • 간접 참조 연산자
  • 주소 연산자
  • 멤버 접근 연산자
  • 첨자 연산자를 사용하는 경우, 피연산자 중 하나가 정수 상수 표현식임

멤버 포인터 상수 표현식 은 한정된 식별자에 주소 연산자를 적용하고, 선택적으로 명시적 멤버 포인터 변환을 앞에 둔 멤버 포인터 타입의 표현식입니다.

(C++11 이전)

다음 표현식들을 총칭하여 상수 표현식(constant expressions) 이라고 합니다:

(C++11부터)
(C++14까지)

다음 개체들은 상수 표현식의 허용된 결과 입니다:

  • 정적 저장 기간 을 가진 임시 객체
  • 아래에 나열된 제약 조건을 만족하는 정적 저장 기간을 가진 비-임시 객체
  • 비- immediate (since C++20) 함수

상수 표현식 은 상수 표현식의 허용된 결과인 개체를 참조하는 glvalue 핵심 상수 표현식 이거나, 다음 제약 조건을 만족하는 prvalue 핵심 상수 표현식입니다:

  • 값이 클래스 타입의 객체인 경우, 참조 타입의 각 비정적 데이터 멤버는 상수 표현식의 허용된 결과인 개체를 참조합니다.
  • 값이 스칼라 타입 의 객체인 경우, indeterminate 값을 가지지 않습니다.
  • 값이 포인터 타입 인 경우, 다음 값 중 하나입니다:
  • 정적 저장 기간을 가진 객체의 주소
  • 정적 저장 기간을 가진 객체의 끝을 지난 주소
  • 비-immediate (since C++20) 함수의 주소
  • null 포인터 값
  • 값이 멤버 함수 포인터 타입인 경우, immediate 함수를 지정하지 않습니다.
(since C++20)
  • 값이 클래스 또는 배열 타입의 객체인 경우, 각 하위 객체는 값에 대해 이러한 제약 조건을 만족합니다.
(since C++14)
(until C++26)

상수 표현식(constant expression) 은 객체나 비- 즉시 함수(immediate function) 을 참조하는 glvalue 핵심 상수 표현식(core constant expression) 이거나, 다음 제약 조건을 만족하는 값을 가지는 prvalue 핵심 상수 표현식입니다:

(C++26부터)

어떤 표현식이 상수 표현식인지 판단할 때, copy elision 이 수행되지 않는 것으로 가정합니다.

C++98 상수 표현식 정의는 접기 상자 내에 완전히 포함되어 있습니다. 다음 설명은 C++11 및 이후 C++ 버전에 적용됩니다.

리터럴 타입

다음 유형들을 통칭하여 literal types 라고 합니다:

  • 이것은 trivial destructor (until C++20) constexpr destructor (since C++20) 를 가집니다.
  • 모든 비정적(non-static) 비변이(non-variant) 데이터 멤버와 기본 클래스가 비휘발성(non-volatile) 리터럴 타입입니다.
  • 다음 타입 중 하나입니다:
(since C++17)
  • variant member 가 없는 경우
  • non-volatile literal type의 variant member를 하나 이상 가진 경우
  • variant member가 없는 경우
  • non-volatile literal type의 variant member를 하나 이상 가진 경우
  • 복사 또는 이동 생성자가 아닌 constexpr 생성자(템플릿)를 하나 이상 가진 타입

리터럴 타입의 객체만 상수 표현식 내에서 생성될 수 있습니다.

코어 상수 표현식

핵심 상수 표현식 은 다음 언어 구성 요소 중 어떠한 것도 평가하지 않는 표현식을 의미합니다:

언어 구성 버전 문서
this 포인터, 단 constexpr 함수 내에서 표현식의 일부로 평가 중이거나, 암시적 또는 명시적 클래스 멤버 접근 표현식에 나타나는 경우는 제외 N2235
정적 또는 스레드 저장 기간 을 가지며 상수 표현식에서 사용 불가능한 블록 변수 선언을 통과하는 제어 흐름 (C++23부터) P2242R3
  1. a function call expression that calls a function (or a constructor) that is not declared constexpr
    constexpr int n = std::numeric_limits<int>::max(); // 정상: max()는 constexpr입니다
    constexpr int m = std::time(nullptr); // 오류: std::time()은 constexpr이 아닙니다
  2. a function call to a constexpr function which is declared, but not defined
  3. a function call to a constexpr function/constructor template instantiation where the instantiation fails to satisfy constexpr 함수/생성자 requirements.
  4. a function call to a constexpr virtual function, invoked on an object whose dynamic type is constexpr-unknown
  5. an expression that would exceed the implementation-defined limits
  6. an expression whose evaluation leads to any form of core language 정의되지 않음 또는 오류가 있는 (C++26부터) behavior, except for any potential undefined behavior introduced by 표준 속성 .
    constexpr double d1 = 2.0 / 1.0; // 정상
    constexpr double d2 = 2.0 / 0.0; // 오류: 정의되지 않음
    constexpr int n = std::numeric_limits<int>::max() + 1; // 오류: 오버플로우
    int x, y, z[30];
    constexpr auto e1 = &y - &x;        // 오류: 정의되지 않음
    constexpr auto e2 = &z[20] - &z[3]; // 정상
    constexpr std::bitset<2> a; 
    constexpr bool b = a[2]; // UB, 하지만 탐지 여부는 명시되지 않음
  7. (C++17 이전) a 람다 표현식
  8. an lvalue-to-rvalue 암시적 변환 unless applied to...
    1. (cv 한정자가 있을 수 있는) 타입의 glvalue std::nullptr_t
    2. 상수 표현식에서 사용 가능한 객체를 지정하는 비휘발성 리터럴 타입 glvalue usable in constant expressions
      int main()
      {
          const std::size_t tabsize = 50;
          int tab[tabsize]; // OK: tabsize is a constant expression
                            // because tabsize is usable in constant expressions
                            // because it has const-qualified integral type, and
                            // its initializer is a constant initializer
          std::size_t n = 50;
          const std::size_t sz = n;
          int tab2[sz]; // Error: sz is not a constant expression
                        // because sz is not usable in constant expressions
                        // because its initializer was not a constant initializer
      }
    3. 이 표현식의 평가 내에서 수명이 시작된 비휘발성 객체를 참조하는 비휘발성 리터럴 타입 glvalue
  9. an lvalue-to-rvalue 암시적 변환 or modification applied to a non-active member of a union or its subobject (even if it shares a common initial sequence with the active member)
  10. an lvalue-to-rvalue implicit conversion on an object 값이 불확정적인
  11. an invocation of implicit copy/move constructor/assignment for a union whose active member is mutable (if any), with lifetime beginning outside the evaluation of this expression
  12. (C++20 이전) an assignment expression that would change the active member of a union
  13. conversion from void에 대한 void 포인터 to a pointer-to-object type T* 포인터가 널 포인터 값을 보유하거나 해당 객체의 타입이 유사한 T 를 가리키지 않는 한 (C++26부터)
  14. dynamic_cast 피연산자가 constexpr-unknown 동적 타입을 가진 객체를 참조하는 glvalue인 (C++20부터)
  15. reinterpret_cast
  16. (C++20 이전) pseudo-destructor call
  17. (C++14 이전) an increment or a decrement operator
  18. (C++14 이후) modification of an object, unless the object has non-volatile literal type and its lifetime began within the evaluation of the expression
    constexpr int incr(int& n)
    {
        return ++n;
    }
    constexpr int g(int k)
    {
        constexpr int x = incr(k); // 오류: incr(k)는 코어 상수 표현식이 아님
                                   // k의 수명이 incr(k) 표현식 외부에서
                                   // 시작되었기 때문
        return x;
    }
    constexpr int h(int k)
    {
        int x = incr(k); // OK: x는 코어 상수 표현식으로 초기화될
                         // 필요가 없음
        return x;
    }
    constexpr int y = h(1); // OK: y를 값 2로 초기화
                            // h(1)은 코어 상수 표현식임
                            // k의 수명이 h(1) 표현식 내부에서 시작되기 때문
  19. (C++20 이후) a destructor call or pseudo destructor call for an object whose lifetime did not begin within the evaluation of this expression
  20. a typeid expression applied to a glvalue of polymorphic type 그리고 그 glvalue가 동적 타입이 constexpr-unknown인 객체를 참조하는 경우 (C++20부터)
  21. a new 표현식 , 다음 조건 중 하나가 충족되지 않는 한: (C++20부터)
    • 선택된 allocation function 이 교체 가능한 전역 할당 함수이며 할당된 저장 공간이 이 표현식 평가 내에서 해제되는 경우.
    (since C++20)
    • 선택된 할당 함수가 할당 타입 T 를 갖는 비할당 형식이며, placement 인자가 다음 모든 조건을 만족하는 경우:
    • 다음을 가리킴:
    • T 가 배열 타입이 아닌 경우, T 와 유사한 타입을 가진 객체, 또는
    • T 가 배열 타입인 경우, T 와 유사한 타입을 가진 객체의 첫 번째 요소.
    • 이 표현식 평가 내에서 지속 시간이 시작된 저장 공간을 가리킴.
    (since C++26)
  22. a delete 표현식 , 단 이 표현식의 평가 내에서 할당된 저장 영역을 해제하는 경우는 제외 (C++20부터)
  23. (C++20 이후) Coroutines: an await-표현식 or a yield-expression
  24. (C++20 이후) a 삼항 비교 when the result is unspecified
  25. an equality or relational operator whose result is unspecified
  26. (C++14 이전) an assignment or a compound assignment operator
  27. (C++26 이전) throw 표현식
  28. (C++26 이후) 예외 객체의 생성. 단, 예외 객체와 std::current_exception 또는 std::rethrow_exception 호출로 생성된 모든 암시적 복사본이 이 표현식 평가 내에서 파괴되는 경우는 제외
    constexpr void check(int i)
    {
        if (i < 0)
            throw i;
    }
    constexpr bool is_ok(int i)
    {
        try {
            check(i);
        } catch (...) {
            return false;
        }
        return true;
    }
    constexpr bool always_throw()
    {
        throw 12;
        return true;
    }
    static_assert(is_ok(5)); // OK
    static_assert(!is_ok(-1)); // C++26부터 OK
    static_assert(always_throw()); // 오류: 처리되지 않은 예외
  29. asm 선언
  30. va_arg 매크로 호출
  31. goto
  32. 예외를 발생시킬 dynamic_cast 또는 typeid 표현식 또는 new 표현식 (C++26 이후) 예외 타입의 정의가 도달 가능하지 않은 경우 (C++26 이후)
  33. 람다 표현식 내부에서, 해당 참조가 odr-use인 경우 this 또는 해당 람다 외부에서 정의된 변수에 대한 참조
    void g()
    {
        const int n = 0;
        constexpr int j = *&n; // OK: 람다 표현식 외부
        [=]
        {
            constexpr int i = n;   // OK: 'n'은 odr-used되지 않으며 여기서 캡처되지 않음
            constexpr int j = *&n; // 잘못된 형식: '&n'은 'n'의 odr-use가 됨
        };
    }

    odr-use가 클로저에 대한 함수 호출에서 발생하는 경우, 이는 this 또는 둘러싸는 변수를 참조하지 않습니다. 클로저의 데이터 멤버에 접근하기 때문입니다

    // OK: 'v'와 'm'은 odr-used되지만 중첩된 람다 내의 상수 표현식에서 발생하지 않음
    // 상수 표현식 평가 중 생성된 자동 객체에 대한 캡처를 가질 수 있음
    auto monad = [](auto v){ return [=]{ return v; }; };
    auto bind = [](auto m){ return [=](auto fvm){ return fvm(m()); }; };
    static_assert(bind(monad(2))(monad)() == monad(2)());
    (C++17 이후)

추가 요구사항

표현식 E 가 위에서 언급된 어떤 것도 평가하지 않더라도, E 를 평가했을 때 런타임-정의되지 않은 동작 이 발생한다면 E 가 핵심 상수 표현인지는 구현에 따라 정의됩니다.

표현식 E 가 위에서 언급한 어떤 것도 평가하지 않더라도, E 를 평가할 경우 다음 중 어떤 것을 평가하게 된다면 E 가 핵심 상수 표현식인지 여부는 명시되지 않습니다:

  • 표준 라이브러리에서 정의되지 않은 동작을 가진 연산.
  • va_start 매크로의 호출.

표현식이 핵심 상수 표현식인지 판단하기 위한 목적으로, std:: allocator < T > 의 멤버 함수 본문 평가는 T 가 리터럴 타입인 경우 무시됩니다.

표현식이 코어 상수 표현식인지 여부를 결정하기 위해, union 의 trivial 복사/이동 생성자 또는 복사/이동 할당 연산자 호출의 평가는 (존재하는 경우) union의 active 멤버를 복사/이동하는 것으로 간주됩니다.

표현식이 핵심 상수 표현(core constant expression)인지 판단하기 위한 목적으로, 구조화된 바인딩(structured binding) bd 를 명명하는 식별자 표현식(identifier expression)의 평가는 다음과 같은 의미론을 가집니다:

  • 만약 bd 가 발명된 참조 ref 에 바인딩된 객체를 참조하는 lvalue라면, ref 가 지명된 것처럼 동작합니다.
  • 그렇지 않고 bd 가 배열 요소를 명명하는 경우, e [ i ] 를 평가하는 것과 같은 동작을 보입니다. 여기서 e 는 구조화된 바인딩 선언의 초기화자로부터 초기화된 변수의 이름이며, i bd 가 참조하는 요소의 인덱스입니다.
  • 그렇지 않고 bd 가 클래스 멤버를 명명하는 경우, e. m 를 평가하는 것과 같은 동작을 보입니다. 여기서 e 는 구조화된 바인딩 선언의 초기화자로부터 초기화된 변수의 이름이며, m bd 가 참조하는 멤버의 이름입니다.
(C++26부터)

표현식이 핵심 상수 표현식으로 평가되는 동안, 모든 식별자 표현식과 수명이 표현식 평가 외부에서 시작된 객체나 참조를 참조하는 * this 사용은 전체 상수 평가를 포함하는 수명을 가진 해당 객체나 참조의 특정 인스턴스를 참조하는 것으로 처리됩니다.

  • 그러한 객체의 경우 상수 표현식에서 사용할 수 없는 객체 (C++20부터) 는 해당 객체의 동적 타입이 constexpr-unknown 입니다.
  • 그러한 참조의 경우 상수 표현식에서 사용할 수 없는 (C++20부터) 참조는 참조된 타입의 지정되지 않은 객체에 바인딩되는 것으로 처리되며, 해당 객체와 모든 하위 객체의 수명은 전체 상수 평가를 포함하고 동적 타입은 constexpr-unknown입니다.

정수 상수 표현식

Integral constant expression 는 정수형 또는 범위 없는 열거형 타입의 표현식이 prvalue로 암시적으로 변환된 것으로, 변환된 표현식이 핵심 상수 표현식인 경우를 말합니다.

클래스 타입의 표현식이 정수 상수 표현식이 필요한 곳에서 사용되면, 해당 표현식은 문맥상 암시적으로 변환됩니다 정수 타입이나 비범위 열거형 타입으로.

변환된 상수 표현식

변환된 상수 표현식 은 타입 T 의 표현식이 암시적으로 변환된 것으로, 변환된 표현식이 상수 표현식이고 암시적 변환 시퀀스가 다음 요소들만 포함하는 경우를 말합니다:

(C++17부터)

그리고 만약 reference binding 이 발생하는 경우, 그것은 오직 direct binding 만 가능합니다.

다음 컨텍스트들은 변환된 상수 표현식이 필요합니다:

(C++14부터)
(C++26부터)

bool 타입의 상황적 변환된 상수 표현식 은 표현식으로, bool로 상황적 변환된 , 변환된 표현식이 상수 표현식이고 변환 순서가 위의 변환들만 포함하는 경우입니다.

다음 상황들은 타입 bool 의 문맥상 변환된 상수 표현식을 요구합니다:

(C++23 이전)
(C++17 이후)
(C++23 이전)
(C++20 이후)


구성 요소

객체 obj 구성 값 은 다음과 같이 정의됩니다:

  • 만약 obj 가 스칼라 타입을 가지면, 구성 값은 obj 의 값입니다.
  • 그렇지 않으면, 구성 값은 서브객체 비활성 유니온 멤버 를 제외한 모든 직접 서브객체의 구성 값입니다.

객체 obj 구성 참조 는 다음 참조들을 포함합니다:

  • obj 의 참조 타입을 가지는 모든 직접 멤버
  • obj 의 비활성 유니온 멤버를 제외한 모든 직접 서브객체의 구성 참조

변수 var 구성 값 구성 참조 는 다음과 같이 정의됩니다:

  • 만약 var 가 객체를 선언하면, 구성 값과 참조는 해당 객체의 구성 값과 참조입니다.
  • 만약 var 가 참조를 선언하면, 구성 참조는 해당 참조입니다.

변수 var 의 구성 참조 ref 에 대해, ref 가 임시 객체나 그 서브객체에 바인딩되고 해당 임시 객체의 수명이 ref 의 수명까지 연장된 경우, 해당 임시 객체의 구성 값과 참조도 재귀적으로 var 의 구성 값과 참조입니다.

Constexpr-표현 가능한 개체

정적 저장 기간을 가지는 객체는 프로그램의 어떤 지점에서든 constexpr-참조 가능 합니다.

자동 저장 기간을 가지는 객체 obj 는 다음 조건을 만족할 때 지점 P 에서 constexpr-참조 가능 합니다: 변수 var 을 포함하는 가장 작은 스코프 P 를 포함하는 가장 작은 스코프가 동일한 함수 매개변수 스코프이며, 이 스코프가 requires 표현식 의 매개변수 목록과 연관되지 않아야 합니다. 여기서 var obj 의 완전한 객체에 해당하는 변수이거나, obj 의 수명이 연장된 변수입니다.

객체나 참조 x 는 다음 모든 조건을 만족할 때 지점 P 에서 constexpr-표현 가능 합니다:

  • x 의 각 구성 값이 객체 obj 를 가리킬 때, obj P 에서 constexpr-참조 가능해야 합니다.
  • x 의 각 구성 값이 객체 obj 를 지나서 가리킬 때, obj P 에서 constexpr-참조 가능해야 합니다.
  • x 의 각 구성 참조가 객체 obj 를 참조할 때, obj P 에서 constexpr-참조 가능해야 합니다.
(C++26부터)

상수 초기화된 엔티티

변수 또는 임시 객체 obj 가 다음 조건을 모두 만족하면 상수 초기화(constant-initialized) 된다:

  • 초기화자를 가지거나, 해당 타입이 const-default-constructible 이어야 한다.
  • 초기화의 전체 표현식(full-expression) 이 상수 표현식이 요구되는 문맥에서 상수 표현식이어야 한다. 단, obj 가 객체인 경우, 해당 전체 표현식은 obj 와 그 하위 객체들에 대해 해당 객체들이 비리터럴 클래스 타입이더라도 constexpr 생성자 를 호출할 수 있다.
(C++26 이전)

변수 var 가 다음 조건을 모두 만족하면 상수 초기화 가능(constant-initializable) 하다:

  • 초기화의 전체 표현식(full-expression) 이 상수 표현식이 요구되는 문맥에서 상수 표현식이어야 하며, 모든 계약 조건(contract assertions) 이 "무시(ignore)" 평가 의미론을 사용해야 한다.
  • var 의 초기화 선언 직후, var 에 의해 선언된 객체 또는 참조가 constexpr-representable이어야 한다.
  • var 에 의해 선언된 객체 또는 참조 x 가 정적 또는 스레드 저장 기간을 가지는 경우, x var 의 초기화 선언 이후에 오는 네임스페이스 범위인 가장 가까운 지점에서 constexpr-representable이어야 한다.

상수 초기화 가능한 변수는 초기화자를 가지거나 해당 타입이 const-default-constructible 인 경우 상수 초기화(constant-initialized) 된다.

(C++26 이후)

상수 표현식에서 사용 가능

변수는 잠재적으로 상수(potentially-constant) 입니다. 만약 그것이 constexpr 변수 이거나 참조 타입이거나 volatile이 아닌 const 한정 정수형 또는 열거형 타입인 경우입니다.

상수 초기화된 잠재적 상수 변수 var 은 다음 조건 중 하나를 만족할 때 P 지점에서 상수 표현식에서 사용 가능 합니다: var 의 초기화 선언 D P 에서 도달 가능하고 다음 조건들 중 하나가 충족되는 경우:

  • var constexpr 변수입니다.
  • var TU-local 값으로 초기화되지 않습니다.
  • P D 와 동일한 번역 단위에 있습니다.

객체 또는 참조는 다음 엔티티들 중 하나일 때 P 지점에서 상수 표현식에서 사용 가능 합니다:

  • P 에서 상수 표현식에서 사용 가능한 변수
  • P 에서 상수 표현식에서 사용 가능한 변수의 수명으로 연장된 비휘발성 const 한정 리터럴 타입의 임시 객체
  • template parameter object
  • string literal 객체
  • 위 항목들 중 어느 것의 비변경 가능한 부분 객체
  • 위 항목들 중 어느 것의 참조 멤버
(C++26까지)

객체 또는 참조는 다음 엔티티들 중 하나일 때 P 지점에서 잠재적으로 상수 표현식에서 사용 가능 합니다:

  • P 에서 상수 표현식에서 사용 가능한 변수
  • P 에서 상수 표현식에서 사용 가능한 변수의 수명으로 연장된 비휘발성 const 한정 리터럴 타입의 임시 객체
  • template parameter object
  • string literal 객체
  • 위 항목들 중 어느 것의 비변경 가능한 부분 객체
  • 위 항목들 중 어느 것의 참조 멤버

객체 또는 참조는 P 지점에서 잠재적으로 상수 표현식에서 사용 가능하며 P 에서 constexpr-representable일 때 P 지점에서 상수 표현식에서 사용 가능 합니다.

(C++26부터)

명시적으로 상수 평가되는 표현식

다음 표현식들(대상 타입으로의 변환을 포함)은 manifestly constant-evaluated 입니다:

평가가 명백하게 상수 평가되는 맥락에서 발생하는지 여부는 std::is_constant_evaluated if consteval (C++23부터) 을 통해 감지할 수 있습니다.

(C++20 이후)

상수 평가에 필요한 함수와 변수

다음 표현식 또는 변환은 잠재적으로 상수 평가될 수 있습니다 :

함수는 constexpr 함수이고 상수 평가될 수 있는 표현식에 의해 이름이 지정된 경우 상수 평가에 필요합니다 .

변수는 상수 평가에 필요합니다 만약 그것이 constexpr 변수이거나, 비휘발성 const 한정 정수 타입이거나 참조 타입이며, 그것을 나타내는 식별자 표현식 이 잠재적으로 상수 평가되는 경우입니다.

디폴트 함수의 정의와 함수 템플릿 특수화의 인스턴스화 또는 변수 템플릿 특수화 (C++14부터) 는 상수 평가를 위해 해당 함수 또는 변수가 (C++14부터) 필요한 경우 트리거됩니다.

상수 부분식

상수 부분식(constant subexpression) 부분식 으로서의 평가가 식 e 핵심 상수 식(core constant expression) 이 되지 못하게 하지 않는 식이며, 여기서 e 는 다음 표현식들 중 어느 것도 아닙니다:

(C++20부터)

참고 사항

기능 테스트 매크로 표준 기능
__cpp_constexpr_in_decltype 201711L (C++20)
(DR11)
상수 평가에 필요할 때 함수 및 변수 정의 생성 needed for constant evaluation
__cpp_constexpr_dynamic_alloc 201907L (C++20) constexpr 함수에서 동적 저장 기간 연산
__cpp_constexpr 202306L (C++26) constexpr void * 캐스트: constexpr 타입 소거를 향하여
202406L (C++26) constexpr 배치 new new [ ]
__cpp_constexpr_exceptions 202411L (C++26) constexpr 예외: [1] , [2]

예제

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 94 C++98 산술 상수 표현식이 변수와 정적 데이터 멤버를
포함할 수 없었음
포함 가능함
CWG 366 C++98 문자열 리터럴을 포함하는 표현식이
정수 상수 표현식일 수 있었음
실제로는 그렇지 않음
CWG 457 C++98 volatile 변수를 포함하는 표현식
정수 상수 표현식이 될 수 있었음
이제는 그렇지 않음
CWG 1293 C++11 문자열 리터럴이 상수 표현식에서
사용 가능한지 여부가 불분명했음
사용 가능함
CWG 1311 C++11 volatile glvalues가 상수 표현식에서 사용될 수 있음 금지됨
CWG 1312 C++11 reinterpret_cast 는 상수 표현식에서 금지되지만,
void * 로의 캐스팅과 void * 로부터의 캐스팅이
동일한 효과를 달성할 수 있음
cv void * 타입으로부터
객체 포인터 타입으로의
금지된 변환
CWG 1313 C++11 정의되지 않은 동작이 허용됨;
모든 포인터 뺄셈이 금지됨
UB 금지; 동일 배열
포인터 뺄셈 허용
CWG 1405 C++11 상수 표현식에서 사용 가능한 객체의 경우,
해당 객체의 mutable 서브객체들도 사용 가능했음
사용 불가능함
CWG 1454 C++11 constexpr 함수를 통해 참조로 상수 전달이
허용되지 않았음
허용됨
CWG 1455 C++11 변환된 상수 표현식은 prvalue만 가능했음 lvalue도 가능함
CWG 1456 C++11 주소 상수 표현식이 배열의 끝 바로 다음 주소를
지정할 수 없었음
허용됨
CWG 1535 C++11 다형적 클래스 타입의 피연산자를 가진
typeid 표현식은 런타임 검사가
포함되지 않은 경우에도 코어 상수 표현식이 아니었음
피연산자 제약 조건이
다형적 클래스 타입의
glvalues로 제한됨
CWG 1581 C++11 상수 평가에 필요한 함수들이
정의되거나 인스턴스화될 필요가 없었음
필수
CWG 1613 C++11 핵심 상수 표현식이 람다 표현식 내부의
odr-used 참조를 평가할 수 있었음
일부 참조를
평가할 수 없었음
CWG 1694 C++11 정적 저장 기간 참조에 임시 객체의 값을 바인딩하는 것이
상수 표현식이었음
상수 표현식이
아님
CWG 1872 C++11 핵심 상수 표현식이 constexpr 함수 요구 사항을 만족하지 않는
함수 템플릿 인스턴스화를 호출할 수 있었음
해당 인스턴스화는
호출할 수 없음
CWG 1952 C++11 표준 라이브러리 정의되지 않은 동작들
진단이 요구됨
진단 여부가 명시되지 않음
(진단되는지 여부가 불명확)
CWG 2022 C++98 상수 표현식 결정이 복사 생략 수행 여부에
의존할 수 있음
복사 생략이 항상
수행된다고 가정
CWG 2126 C++11 상수 초기화된 수명이 연장된 const-한정 리터럴 타입의 임시 객체들이
상수 표현식에서 사용 불가능했음
사용 가능
CWG 2129 C++11 정수 리터럴이 상수 표현식이 아니었음 상수 표현식임
CWG 2167 C++11 평가에 지역적인 비멤버 참조
평가를 비 constexpr로 만듦
비멤버
참조 허용됨
CWG 2278 C++98 CWG 이슈 2022 의 해결책이 구현 불가능했음 복사 생략(copy elision)이
수행되지 않는다고 가정
CWG 2299 C++14 상수 평가에서 <cstdarg>
매크로 사용 가능 여부가 불명확했음
va_arg 금지,
va_start 미지정
CWG 2400 C++11 상수 표현식에서 사용 가능하지 않은 객체와 그 수명이 호출을 포함하는
표현식 외부에서 시작된 객체에서 constexpr 가상 함수를 호출하는 것은
상수 표현식일 수 있음
상수 표현식이
아님
CWG 2490 C++20 상수 평가에서 (의사) 소멸자 호출에
제한이 없었음
제한 추가됨
CWG 2552 C++23 핵심 상수 표현식을 평가할 때, 제어 흐름이
비블록 변수의 선언을 통과할 수 없음
가능함
CWG 2558 C++11 불확정 값이 상수 표현식일 수 있음 상수 표현식이 아님
CWG 2647 C++20 volatile 한정 타입의 변수들이 잠재적으로 상수일 수 있음 실제로는 그렇지 않음
CWG 2763 C++11 상수 평가 중 [[ noreturn ]] 위반을 검출할 필요가 없었음
필수
CWG 2851 C++11 변환된 상수 표현식이
부동 소수점 변환을 허용하지 않음
비축소(non-narrowing)
부동 소수점 변환 허용
CWG 2907 C++11 핵심 상수 표현식이
std::nullptr_t glvalue에 대해
lvalue-to-rvalue 변환을 적용할 수 없었음
해당 변환을
적용할 수 있음
CWG 2909 C++20 초기화자가 없는 변수는 기본 초기화가
일부 초기화를 수행하는 경우에만
상수 초기화될 수 있었음
해당 타입이 const-기본-초기화-가능한
경우에만 상수 초기화될 수 있음
CWG 2924 C++11
C++23
제약 조건을 위반하는 표현식이
[[ noreturn ]] (C++11) 또는
[[ assume ]] (C++23)의 핵심 상수 표현식인지 여부가 명시되지 않았음
이는
구현에 따라 정의됨
P2280R4 C++11 이 평가 외부에서 수명이 시작된 객체나 참조를 참조하는
식별자 표현식이나 * this 를 포함하는 표현식을 평가하는 것은
상수 표현식이 아님
상수 표현식이
될 수 있음

참고 항목

constexpr 지정자 (C++11) 변수나 함수의 값을 컴파일 시간에 계산할 수 있음을 지정함
(C++11) (C++17에서 사용 중단됨) (C++20에서 제거됨)
타입이 리터럴 타입인지 검사함
(클래스 템플릿)
C 문서 for 상수 표현식