수색…
소개
constexpr
은 변수의 값을 상수 표현식이나 상수 표현식에서 잠재적으로 사용할 수있는 함수로 표시하는 데 사용할 수있는 키워드 이거나 if 문 을 컴파일하도록 선택한 분기 중 하나만 가지고있는 것으로 (C ++ 17 이후) 선언 합니다.
비고
constexpr
키워드는 C ++ 11에 추가되었지만 C ++ 11 표준이 발표 된 이후 몇 년 동안 모든 주요 컴파일러가 지원하지는 않았습니다. C ++ 11 표준이 발표 된 시점에 C ++ 14의 발행 시점에 모든 주요 컴파일러는 constexpr
지원합니다.
constexpr 변수
constexpr
로 선언 된 변수는 암시 적으로 const
이며 그 값은 상수 표현으로 사용될 수 있습니다.
#define
과의 비교
constexpr
은 #define
기반 컴파일 타임 표현식에 대한 타입 안전 대체입니다. constexpr
하면 컴파일 타임으로 계산 된 표현식이 결과로 바뀝니다. 예 :
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
사용할 수는 있지만 함정이 있습니다.
따라서 다음을 사용하십시오.
int main()
{
constexpr int size = 10;
int arr[size];
}
constexpr
표현식은 컴파일 타임 값으로 평가되어야합니다. 따라서 다음을 사용할 수 없습니다.
constexpr int size = abs(10);
함수 ( abs
) 자체가 constexpr
반환하지 않으면.
모든 기본 유형은 constexpr
하여 초기화 할 수 있습니다.
constexpr bool FailFatal = true;
constexpr float PI = 3.14f;
constexpr char* site= "StackOverflow";
흥미롭게도 편리 auto
를 사용할 수 있습니다.
constexpr auto domain = ".COM"; // const char * const domain = ".COM"
constexpr auto PI = 3.14; // constexpr double
constexpr 함수
constexpr
로 선언 된 함수는 암시 적으로 인라인이며 이러한 함수를 호출하면 잠재적으로 상수 표현이 생성됩니다. 예를 들어 상수 표현식 인수와 함께 호출 된 경우 다음 함수는 상수 표현식도 생성합니다.
constexpr int Sum(int a, int b)
{
return a + b;
}
따라서 함수 호출의 결과는 배열 바운드 또는 템플릿 인수로 사용되거나 constexpr
변수를 초기화 할 수 있습니다.
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 할당해야합니다. 마찬가지로 함수의 Sum
이 constexpr
이 아닌 경우 array의 크기도 상수 표현이 아닙니다.
constexpr
함수에 대한 흥미로운 점은 일반 함수처럼 사용할 수도 있다는 것입니다.
int a = 20;
auto sum = Sum(a, abs(-20));
Sum
은 현재 constexpr
함수가 아니며, 일반 함수로 컴파일되고, 변수가 아닌 (불변의) 인수를 취하고, 상수가 아닌 값을 반환합니다. 두 가지 기능을 작성할 필요가 없습니다.
또한 const가 아닌 변수에 이러한 호출을 할당하려고하면 컴파일되지 않습니다.
int a = 20;
constexpr auto sum = Sum(a, abs(-20));
그 이유는 간단합니다 : constexpr
에는 컴파일 타임 상수 만 지정해야합니다. 그러나 위 함수 호출은 Sum
을 비 constexpr
만듭니다 (R 값은 const가 아니지만 L 값은 constexpr
선언됩니다).
constexpr
함수 는 컴파일 타임 상수도 반환 해야합니다 . 다음은 컴파일되지 않습니다.
constexpr int Sum(int a, int b)
{
int a1 = a; // ERROR
return a + b;
}
왜냐하면 a1
은 constexpr이 아닌 변수 이기 때문에 함수가 실제 constexpr
함수가되는 것을 금지하기 때문입니다. 그것을 만들기 constexpr
그것에게 할당 도 작동하지 않습니다 - 값 때문에 (입력 매개 변수) 아직 불명입니다 : a
a
constexpr int Sum(int a, int b)
{
constexpr int a1 = a; // ERROR
..
또한 다음은 컴파일되지 않습니다.
constexpr int Sum(int a, int b)
{
return abs(a) + b; // or abs(a) + abs(b)
}
abs(a)
는 상수 표현이 아니기 때문에 (심지어 abs(10)
도 작동하지 않을 것입니다. 왜냐하면 abs
가 constexpr int
반환하지 않기 때문입니다!
이건 어때?
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 문
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
}