constexpr
specifier
(since C++11)
-
-
constexpr- 변수의 값 , structured binding (since C++26) 또는 함수가 constant expressions 에 나타날 수 있음을 지정합니다
-
목차 |
설명
constexpr 지정자는 해당 개체들의 값을 컴파일 시간에 평가할 수 있음을 선언합니다. 그러한 개체들은 오직 컴파일 시간 상수 표현식 만 허용되는 곳에서 사용될 수 있습니다 (적절한 함수 인수가 제공되는 경우).
객체 선언에서 사용된 constexpr 지정자는 또는 비정적 멤버 함수 (C++14까지) 가 const 를 암시합니다.
함수의 첫 번째 선언에서 사용된 constexpr 지정자는 또는 static 데이터 멤버 (C++17부터) 가 inline 을 암시합니다. 함수 또는 함수 템플릿의 선언에 constexpr 지정자가 있는 경우, 모든 선언은 해당 지정자를 포함해야 합니다.
constexpr 변수
변수 또는 변수 템플릿 (C++14 이후) 는 다음 모든 조건이 충족될 경우 constexpr 로 선언될 수 있습니다:
- 선언은 정의 입니다.
- 이것은 literal type 입니다.
- (선언에 의해) 초기화됩니다.
|
(C++26까지) |
|
(C++26부터) |
|
constexpr 변수가 번역 단위 지역적(translation-unit-local) 이 아닌 경우, 상수 표현식에서 사용 가능한 번역 단위 지역적 개체를 참조하도록 초기화되어서는 안 되며, 그러한 개체를 참조하는 하위 객체를 가져서도 안 됩니다. 이러한 초기화는 모듈 인터페이스 단위(module interface unit) (해당 비공개 모듈 조각(private module fragment) 외부) 또는 모듈 파티션에서 허용되지 않으며, 다른 모든 상황에서는 사용이 권장되지 않습니다. |
(C++20부터) |
constexpr 함수
함수 또는 함수 템플릿은 constexpr 로 선언될 수 있습니다.
함수는 다음 조건을 모두 만족할 경우 constexpr-suitable 입니다:
|
(C++20 이전) |
|
(C++23 이전) |
|
(C++20 이후) |
|
(C++14까지) | ||
|
(C++14부터)
(C++23까지) |
인스턴스화된 constexpr 함수를 제외하고, 비템플릿 constexpr 함수는 constexpr-suitable해야 합니다.
|
생성자가 아닌 constexpr 함수가 기본 구현되지도 않고 템플릿화되지도 않은 경우, 함수 호출이 핵심 상수 표현식 의 평가된 하위 표현식이 될 수 있는 인수 값이 존재하지 않으면, 프로그램의 형식이 잘못되었으며 진단이 필요하지 않습니다. 템플릿화된 constexpr 함수의 경우, 함수/클래스 템플릿의 어떤 특수화도 비템플릿 함수로 간주할 때 해당 템플릿 함수를 constexpr-적합하게 만들 수 없다면, 프로그램의 형식이 잘못되었으며 진단이 필요하지 않습니다. |
(C++23까지) |
주어진 맥락에서 constexpr 함수의 호출은 다음 예외를 제외한 모든 측면에서 동일한 맥락에서의 동등한 비- constexpr 함수 호출과 동일한 결과를 생성합니다:
constexpr 생성자
constexpr 함수의 요구사항 외에도, 생성자가 constexpr로 적합하려면 다음 모든 조건을 충족해야 합니다:
|
(C++23까지) |
- 해당 클래스는 virtual base class 를 가지고 있지 않습니다.
|
기본 설정되지 않거나 템플릿화되지 않은 constexpr 생성자의 경우, 함수 호출이 상수 표현식 의 대상인 일부 객체의 초기화 전체 표현식의 평가된 하위 표현식이 될 수 있는 인수 값이 존재하지 않으면, 프로그램의 형식이 잘못되었으며 진단이 필요하지 않습니다. |
(C++23까지) |
constexpr 소멸자
|
소멸자는 constexpr 로 선언할 수 없지만, trivial destructor 는 상수 표현식에서 암시적으로 호출될 수 있습니다. |
(C++20 이전) | ||
|
constexpr 함수의 요구사항에 더하여, 소멸자가 constexpr-suitable이 되기 위해서는 다음 모든 조건을 추가로 만족해야 합니다:
|
(C++20 이후) |
참고 사항
|
constexpr int f(); constexpr bool b1 = noexcept(f()); // false, undefined constexpr function constexpr int f() { return 0; } constexpr bool b2 = noexcept(f()); // true, f() is a constant expression |
(C++17까지) |
|
코어 상수 표현식의 요구사항을 절대 만족시킬 수 없는 constexpr 함수를 작성하는 것이 가능합니다: void f(int& i) // not a constexpr function { i = 0; } constexpr void g(int& i) // well-formed since C++23 { f(i); // unconditionally calls f, cannot be a constant expression } |
(C++23부터) |
리터럴 타입이 아닌 클래스에 대해 constexpr 생성자가 허용됩니다. 예를 들어, std::shared_ptr 의 기본 생성자는 constexpr이며, 이를 통해 상수 초기화 가 가능합니다.
참조 변수는 constexpr로 선언될 수 있습니다(이들의 초기화자는 참조 상수 표현식 이어야 함):
static constexpr int const& x = 42; // constexpr 참조를 통한 const int 객체 참조 // (정적 참조에 의한 수명 연장으로 인해 // 해당 객체는 정적 저장 기간을 가짐)
|
try 블록과 인라인 어셈블리가 constexpr 함수에서 허용되지만, 예외를 던지는 것 (catch되지 않는) (C++26부터) 또는 어셈블리 실행은 상수 표현식에서 여전히 허용되지 않습니다. 변수가 상수 소멸을 가지는 경우, 해당 소멸자가 trivial하지 않더라도 소멸자를 호출하기 위해 기계어 코드를 생성할 필요가 없습니다. 비-람다, 비-특별 멤버, 비-템플릿 constexpr 함수는 암시적으로 즉시 함수가 될 수 없습니다. 사용자는 그러한 의도된 함수 정의를 올바르게 만들기 위해 명시적으로 consteval 으로 표시해야 합니다. |
(C++20부터) |
| 기능 테스트 매크로 | 값 | 표준 | 기능 |
|---|---|---|---|
__cpp_constexpr
|
200704L
|
(C++11) | constexpr |
201304L
|
(C++14) | 완화된 constexpr , non- const constexpr 메서드 | |
201603L
|
(C++17) | Constexpr 람다 | |
201907L
|
(C++20) | 단순 기본 초기화 및 asm 선언 in constexpr 함수 | |
202002L
|
(C++20) | 상수 평가에서 union의 활성 멤버 변경 | |
202110L
|
(C++23) | Non- literal 변수, 레이블 및 goto 문 in constexpr 함수 | |
202207L
|
(C++23) | 일부 constexpr 제한 완화 | |
202211L
|
(C++23) | static constexpr 변수 in constexpr 함수 허용 | |
202306L
|
(C++26) | void * 에서의 Constexpr 캐스트: constexpr 타입 소거를 향하여 | |
__cpp_constexpr_in_decltype
|
201711L
|
(C++11)
(DR) |
상수 평가에 필요한 경우 함수 및 변수 정의 생성 |
__cpp_constexpr_dynamic_alloc
|
201907L
|
(C++20) | constexpr 함수에서 동적 저장 기간 연산 |
키워드
예제
C++11/14 constexpr 함수들을 정의하여 팩토리얼을 계산합니다; 문자열 리터럴을 확장하는 리터럴 타입을 정의합니다:
#include <iostream> #include <stdexcept> // C++11 constexpr 함수들은 반복 대신 재귀를 사용합니다 constexpr int factorial(int n) { return n <= 1 ? 1 : (n * factorial(n - 1)); } // C++14 constexpr 함수들은 지역 변수와 반복문을 사용할 수 있습니다 #if __cplusplus >= 201402L constexpr int factorial_cxx14(int n) { int res = 1; while (n > 1) res *= n--; return res; } #endif // C++14 // 리터럴 클래스 class conststr { const char* p; std::size_t sz; public: template<std::size_t N> constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {} // constexpr 함수들은 예외를 던져서 오류를 신호합니다 // C++11에서는 조건 연산자 ?:에서 그렇게 해야 합니다 constexpr char operator[](std::size_t n) const { return n < sz ? p[n] : throw std::out_of_range(""); } constexpr std::size_t size() const { return sz; } }; // C++11 constexpr 함수들은 모든 것을 단일 return 문에 넣어야 했습니다 // (C++14에는 그런 요구사항이 없습니다) constexpr std::size_t countlower(conststr s, std::size_t n = 0, std::size_t c = 0) { return n == s.size() ? c : 'a' <= s[n] && s[n] <= 'z' ? countlower(s, n + 1, c + 1) : countlower(s, n + 1, c); } // 컴파일 타임 상수가 필요한 출력 함수, 테스트용 template<int n> struct constN { constN() { std::cout << n << '\n'; } }; int main() { std::cout << "4! = "; constN<factorial(4)> out1; // 컴파일 타임에 계산됨 volatile int k = 8; // volatile을 사용하여 최적화 방지 std::cout << k << "! = " << factorial(k) << '\n'; // 런타임에 계산됨 std::cout << "\"Hello, world!\"의 소문자 개수는 "; constN<countlower("Hello, world!")> out2; // 암시적으로 conststr로 변환됨 constexpr int a[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; constexpr int length_a = sizeof a / sizeof(int); // C++17에서는 std::size(a), // C++20에서는 std::ssize(a) std::cout << "길이 " << length_a << "인 배열의 원소들: "; for (int i = 0; i < length_a; ++i) std::cout << a[i] << ' '; std::cout << '\n'; }
출력:
4! = 24 8! = 40320 "Hello, world!"의 소문자 개수는 9입니다 길이가 12인 배열의 요소: 0 1 2 3 4 5 6 7 8 0 0 0
결함 보고서
다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.
| DR | 적용 대상 | 게시된 동작 | 올바른 동작 |
|---|---|---|---|
| CWG 1358 | C++11 |
템플릿화된
constexpr
함수들도 적어도 하나의 유효한
인수 값을 가져야 했음 |
필요 없음 |
| CWG 1359 | C++11 |
constexpr
공용체 생성자들은 모든 데이터 멤버를
초기화해야 했음 |
비어 있지 않은 공용체의 경우 정확히 하나의
데이터 멤버만 초기화 |
| CWG 1366 | C++11 |
함수 본문이
=
default
또는
=
delete
인
constexpr
생성자를 가진
클래스들이 가상 기본 클래스를 가질 수 있었음 |
해당 클래스들은 가상 기본 클래스를
가질 수 없음 |
| CWG 1595 | C++11 |
constexpr
위임 생성자들은 관련된 모든 생성자들이
constexpr 이어야 했음 |
대상 생성자만 constexpr 이면 됨 |
| CWG 1712 | C++14 |
constexpr
변수 템플릿은 모든 선언에
constexpr
지정자를
포함해야 했음 [1] |
더 이상 요구되지 않음 |
| CWG 1911 | C++11 | 리터럴이 아닌 타입들에 대한 constexpr 생성자들이 허용되지 않았음 | 상수 초기화에서 허용됨 |
| CWG 2004 | C++11 |
mutable 멤버를 가진 공용체의 복사/이동이
상수 표현식에서 허용되었음 |
mutable 변형들이 암시적 복사/이동을
부적격하게 만듦 |
| CWG 2022 | C++98 |
동등한
constexpr
와 비-
constexpr
함수가 동일한 결과를
생성하는지 여부가 복사 생략 수행 여부에 의존할 수 있었음 |
상수 표현식에서는 복사 생략이 항상
수행된다고 가정 |
| CWG 2163 | C++14 |
goto
문이 금지되어 있음에도
constexpr
함수에서
레이블들이 허용되었음 |
레이블들도 금지됨 |
| CWG 2268 | C++11 |
mutable 멤버를 가진 공용체의 복사/이동이
CWG 이슈 2004 의 해결에 의해 금지되었음 |
객체가 상수 표현식 내에서 생성된
경우 허용됨 |
| CWG 2278 | C++98 | CWG 이슈 2022 의 해결이 구현 가능하지 않았음 |
상수 표현식에서는 복사 생략이 절대
수행되지 않는다고 가정 |
| CWG 2531 | C++11 |
비-인라인 변수가
constexpr
로 재선언되면
인라인이 됨 |
변수가 인라인이
되지 않음 |
- ↑ 이는 constexpr 지정자를 가진 변수 템플릿의 선언이 둘 이상 존재할 수 없기 때문에 중복됩니다.
참고 항목
| constant expression | 컴파일 타임에 평가될 수 있는 표현식 을 정의함 |
consteval
specifier
(C++20)
|
함수가 immediate function 임을 지정하며, 함수에 대한 모든 호출이 상수 평가에서 이루어져야 함 |
constinit
specifier
(C++20)
|
변수가 정적 초기화, 즉 zero initialization 과 constant initialization 을 가짐을 단언함 |
|
C documentation
for
constexpr
|
|