다음 정의 사이에 차이점이 있습니까?
const double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;
그렇지 않다면 C ++ 11에서 어떤 스타일이 선호됩니까?
다음 정의 사이에 차이점이 있습니까?
const double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;
그렇지 않다면 C ++ 11에서 어떤 스타일이 선호됩니까?
답변:
차이가 있다고 생각합니다. 더 쉽게 이야기 할 수 있도록 이름을 바꾸겠습니다.
const double PI1 = 3.141592653589793;
constexpr double PI2 = 3.141592653589793;
모두 PI1
와 PI2
당신이 그들을 수정할 수 없습니다 의미 상수입니다. 그러나 단지 PI2
컴파일 타임 상수이다. 그것은 해야 컴파일시에 초기화 될 수있다. PI1
컴파일 타임 또는 런타임에 초기화 될 수 있습니다. 또한 컴파일 타임 상수가 필요한 컨텍스트 에서만 PI2
사용할 수 있습니다. 예를 들면 다음과 같습니다.
constexpr double PI3 = PI1; // error
그러나:
constexpr double PI3 = PI2; // ok
과:
static_assert(PI1 == 3.141592653589793, ""); // error
그러나:
static_assert(PI2 == 3.141592653589793, ""); // ok
어느 쪽을 사용해야합니까? 필요에 맞는 것을 사용하십시오. 컴파일 타임 상수가 필요한 상황에서 사용할 수있는 컴파일 타임 상수가 있는지 확인 하시겠습니까? 런타임에 수행 된 계산으로 초기화 할 수 있습니까? 기타.
const int N = 10; char a[N];
작동 하기 때문에 배열 범위는 컴파일 타임 상수 여야합니다.
PI1
배열에서 사용하기 위해 컴파일 타임 정수 상수 로 변환 할 수 있지만 비 유형 정수 템플릿 매개 변수로는 사용할 수 없습니다. 따라서 PI1
정수 형으로 의 컴파일 타임 변환 가능성은 약간 히트하고 그리워 보입니다.
enum
이니셜 라이저로 사용하는 것은 const
and 사이의 유일한 두 가지 차이점 constexpr
입니다 ( double
어쨌든 작동하지 않습니다 ).
1 / PI1
와 1 / PI2
다른 결과를 얻을 수 있습니다. 그러나이 기술 이이 답변의 조언만큼 중요하지 않다고 생각합니다.
constexpr double PI3 = PI1;
나를 위해 올바르게 작동합니다. (MSVS2013 CTP). 내가 뭘 잘못하고 있죠?
여기에는 차이가 없지만 생성자가있는 형식이있을 때 중요합니다.
struct S {
constexpr S(int);
};
const S s0(0);
constexpr S s1(1);
s0
상수이지만 컴파일 타임에 초기화되지는 않습니다. s1
로 표시 constexpr
되므로 상수이며 S
의 생성자도 표시 되므로constexpr
있으므로 컴파일 타임에 초기화됩니다.
대부분 런타임에 초기화하는 데 시간이 많이 걸리고 컴파일러로 작업을 푸시하려고 할 때 중요합니다.이 작업은 시간이 많이 걸리지 만 컴파일 된 프로그램의 실행 시간을 늦추지는 않습니다.
constexpr
은 객체의 컴파일 타임 계산이 불가능할 경우 진단으로 이어질 것이라는 것이었다 . 덜 명확한 것은 상수 매개 변수를 기대 하는 함수 가 컴파일 타임에 실행될 수 있는지 여부는 매개 변수를 다음 const
과 같이 선언 하지 말고 선언해야한다는 constexpr
것입니다. 즉, constexpr int foo(S)
호출하면 컴파일 타임에 실행 foo(s0)
됩니까?
foo(s0)
컴파일 타임에 실행 될지 의심 스럽지만 알 수 없습니다. 컴파일러는 그러한 최적화를 수행 할 수 있습니다. 확실히 gcc 4.7.2 나 clang 3.2는 컴파일 할 수 없습니다constexpr a = foo(s0);
constexpr 은 상수이며 컴파일 중에 알려진 값을 나타냅니다.
const 는 상수 인 값을 나타냅니다. 컴파일하는 동안 반드시 알아야하는 것은 아닙니다.
int sz;
constexpr auto arraySize1 = sz; // error! sz's value unknown at compilation
std::array<int, sz> data1; // error! same problem
constexpr auto arraySize2 = 10; // fine, 10 is a compile-time constant
std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr
const는 constexpr과 동일한 보장을 제공하지 않습니다. const 객체는 컴파일 중에 알려진 값으로 초기화 될 필요가 없기 때문입니다.
int sz;
const auto arraySize = sz; // fine, arraySize is const copy of sz
std::array<int, arraySize> data; // error! arraySize's value unknown at compilation
모든 constexpr 객체는 const이지만 모든 constexpr 객체는 constexpr이 아닙니다.
컴파일러가 변수에 컴파일 타임 상수가 필요한 컨텍스트에서 사용할 수있는 값을 갖도록하려면, 도달 할 도구는 const가 아닌 constexpr입니다.
constexpr 기호 상수는 컴파일 타임에 알려진 값을 제공해야합니다. 예를 들면 다음과 같습니다.
constexpr int max = 100;
void use(int n)
{
constexpr int c1 = max+7; // OK: c1 is 107
constexpr int c2 = n+7; // Error: we don’t know the value of c2
// ...
}
컴파일 타임에는 알려지지 않았지만 초기화 후에도 변경되지 않는 값으로 초기화되는 "변수"의 값을 처리하기 위해 C ++은 두 번째 형태의 상수 ( const )를 제공합니다. 예를 들어 :
constexpr int max = 100;
void use(int n)
{
constexpr int c1 = max+7; // OK: c1 is 107
const int c2 = n+7; // OK, but don’t try to change the value of c2
// ...
c2 = 7; // error: c2 is a const
}
이러한“ const 변수”는 다음 두 가지 이유로 매우 일반적입니다.
참조 : Stroustrup의 "프로그래밍 : C ++을 사용한 원리 및 실습"