수색…


소개

constexpr 은 변수의 값을 상수 표현식이나 상수 표현식에서 잠재적으로 사용할 수있는 함수로 표시하는 데 사용할 수있는 키워드 이거나 if 문 을 컴파일하도록 선택한 분기 중 하나만 가지고있는 것으로 (C ++ 17 이후) 선언 합니다.

비고

constexpr 키워드는 C ++ 11에 추가되었지만 C ++ 11 표준이 발표 된 이후 몇 년 동안 모든 주요 컴파일러가 지원하지는 않았습니다. C ++ 11 표준이 발표 된 시점에 C ++ 14의 발행 시점에 모든 주요 컴파일러는 constexpr 지원합니다.

constexpr 변수

constexpr 로 선언 된 변수는 암시 적으로 const 이며 그 값은 상수 표현으로 사용될 수 있습니다.

#define 과의 비교

constexpr#define 기반 컴파일 타임 표현식에 대한 타입 안전 대체입니다. constexpr 하면 컴파일 타임으로 계산 된 표현식이 결과로 바뀝니다. 예 :

C ++ 11
int main()
{
   constexpr int N = 10 + 2;
   cout << N;
}

다음 코드를 생성합니다.

cout << 12;

프리 프로세서 기반 컴파일 타임 매크로는 다를 수 있습니다. 중히 여기다:

#define N 10 + 2

int main()
{
    cout << N;
}

생산할 것이다 :

cout << 10 + 2;

이것은 분명히 cout << 10 + 2; 로 변환 될 것이다 cout << 10 + 2; . 그러나 컴파일러는 더 많은 작업을 수행해야합니다. 또한 올바르게 사용하지 않으면 문제가 발생합니다.

예를 들어 ( #define ) :

cout << N * 2;

양식 :

cout << 10 + 2 * 2; // 14

그러나 미리 평가 된 constexpr 는 정확하게 24 줄 것입니다.

const 와의 비교

const 변수는 저장을위한 메모리가 필요한 변수 입니다. constexpr 은 그렇지 않습니다. constexpr 은 컴파일 시간 상수를 생성하며 변경할 수 없습니다. const 가 변경되지 않을 수도 있다고 주장 할 수 있습니다. 그러나 고려하십시오 :

int main()
{
   const int size1 = 10;
   const int size2 = abs(10);

   int arr_one[size1]; 
   int arr_two[size2]; 
}

대부분의 컴파일러에서는 두 번째 명령문이 실패합니다 (예 : GCC에서 작동 할 수 있음). 알고있는 모든 배열의 크기는 상수 표현식이어야합니다 (즉, 컴파일시 값이됩니다). 두 번째 변수 size2 는 런타임에 결정되는 값을 할당받습니다 (컴파일러의 경우 컴파일 타임이 아니라는 것을 알지만 10 ).

이것은 const 가 실제 컴파일 타임 상수 일 수도 있고 그렇지 않을 수도 있음을 의미합니다. 특정 const 값이 절대적으로 컴파일 타임임을 보장하거나 강요 할 수는 없습니다. #define 사용할 수는 있지만 함정이 있습니다.

따라서 다음을 사용하십시오.

C ++ 11
int main()
{
    constexpr int size = 10;

    int arr[size];
}

constexpr 표현식은 컴파일 타임 값으로 평가되어야합니다. 따라서 다음을 사용할 수 없습니다.

C ++ 11
constexpr int size = abs(10);

함수 ( abs ) 자체가 constexpr 반환하지 않으면.

모든 기본 유형은 constexpr 하여 초기화 할 수 있습니다.

C ++ 11
constexpr bool FailFatal = true;
constexpr float PI = 3.14f;
constexpr char* site= "StackOverflow";

흥미롭게도 편리 auto 를 사용할 수 있습니다.

C ++ 11
constexpr auto domain = ".COM";  // const char * const domain = ".COM"
constexpr auto PI = 3.14;        // constexpr double

constexpr 함수

constexpr 로 선언 된 함수는 암시 적으로 인라인이며 이러한 함수를 호출하면 잠재적으로 상수 표현이 생성됩니다. 예를 들어 상수 표현식 인수와 함께 호출 된 경우 다음 함수는 상수 표현식도 생성합니다.

C ++ 11
constexpr int Sum(int a, int b)
{
    return a + b;
}

따라서 함수 호출의 결과는 배열 바운드 또는 템플릿 인수로 사용되거나 constexpr 변수를 초기화 할 수 있습니다.

C ++ 11
int main()
{
    constexpr int S = Sum(10,20);
   
    int Array[S];
    int Array2[Sum(20,30)]; // 50 array size, compile time
}

당신이 제거하면 있습니다 constexpr 함수의 반환 형식 사양에서을에 할당 S 같이 작동하지 않습니다 S A는 constexpr 변수 및 컴파일 시간을 const 할당해야합니다. 마찬가지로 함수의 Sumconstexpr 이 아닌 경우 array의 크기도 상수 표현이 아닙니다.

constexpr 함수에 대한 흥미로운 점은 일반 함수처럼 사용할 수도 있다는 것입니다.

C ++ 11
int a = 20;
auto sum = Sum(a, abs(-20));

Sum 은 현재 constexpr 함수가 아니며, 일반 함수로 컴파일되고, 변수가 아닌 (불변의) 인수를 취하고, 상수가 아닌 값을 반환합니다. 두 가지 기능을 작성할 필요가 없습니다.

또한 const가 아닌 변수에 이러한 호출을 할당하려고하면 컴파일되지 않습니다.

C ++ 11
int a = 20;
constexpr auto sum = Sum(a, abs(-20));

그 이유는 간단합니다 : constexpr 에는 컴파일 타임 상수 만 지정해야합니다. 그러나 위 함수 호출은 Sum 을 비 constexpr 만듭니다 (R 값은 const가 아니지만 L 값은 constexpr 선언됩니다).


constexpr 함수 컴파일 타임 상수도 반환 해야합니다 . 다음은 컴파일되지 않습니다.

C ++ 11
constexpr int Sum(int a, int b)
{
    int a1 = a;     // ERROR
    return a + b;
}

왜냐하면 a1 은 constexpr이 아닌 변수 이기 때문에 함수가 실제 constexpr 함수가되는 것을 금지하기 때문입니다. 그것을 만들기 constexpr 그것에게 할당 도 작동하지 않습니다 - 값 때문에 (입력 매개 변수) 아직 불명입니다 : a a

C ++ 11
constexpr int Sum(int a, int b)
{
   constexpr int a1 = a;     // ERROR
   ..

또한 다음은 컴파일되지 않습니다.

C ++ 11
constexpr int Sum(int a, int b)
{
   return abs(a) + b; // or abs(a) + abs(b)
}

abs(a) 는 상수 표현이 아니기 때문에 (심지어 abs(10) 도 작동하지 않을 것입니다. 왜냐하면 absconstexpr int 반환하지 않기 때문입니다!

이건 어때?

C ++ 11
constexpr int Abs(int v)
{
    return v >= 0 ? v : -v;
}

constexpr int Sum(int a, int b)
{
    return Abs(a) + b;
}

우리는 constexpr 인 우리 자신의 Abs 함수를 constexpr , Abs 의 몸체는 규칙을 위반하지 않습니다. 또한 콜 사이트 ( Sum )에서 표현식은 constexpr 평가됩니다. 따라서 Sum(-10, 20) 대한 호출은 컴파일 타임 상수 표현으로 30 됩니다.

정적 if 문

C ++ 17

if constexpr 문을 사용하여 조건부로 코드를 컴파일 할 수 있습니다. 조건은 상수 표현이어야합니다. 선택되지 않은 분기는 버려집니다. 템플리트 내의 삭제 된 명령문은 인스턴스화되지 않습니다. 예 :

template<class T, class ... Rest>
void g(T &&p, Rest &&...rs)
{
  // ... handle p
  if constexpr (sizeof...(rs) > 0)
    g(rs...);  // never instantiated with an empty argument list
}

또한, 폐기 된 문장 내에서만 odr- 사용되는 변수와 함수는 정의 될 필요가 없으며, 폐기 된 return 문은 함수 반환 유형 공제에 사용되지 않습니다.

if constexpr#ifdef 와 구별되는 if constexpr . #ifdef 조건부로 코드를 컴파일하지만 전처리 시간에 평가할 수있는 조건을 기반으로합니다. 예를 들어 #ifdef 는 템플릿 매개 변수의 값에 따라 조건부로 코드를 컴파일하는 데 사용할 수 없습니다. 반면에 if constexpr 은 구문 적으로 유효하지 않은 코드를 버리는 데 사용할 수 없지만 #ifdef 는 사용할 수 있습니다.

if constexpr(false) {
    foobar;  // error; foobar has not been declared
    std::vector<int> v("hello, world");  // error; no matching constructor
}


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow