변수에 대한 const vs constexpr double PI

다음 정의 사이에 차이점이 있습니까?

const     double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;

그렇지 않다면 C ++ 11에서 어떤 스타일이 선호됩니까?



답변

차이가 있다고 생각합니다. 더 쉽게 이야기 할 수 있도록 이름을 바꾸겠습니다.

const     double PI1 = 3.141592653589793;
constexpr double PI2 = 3.141592653589793;

모두 PI1PI2당신이 그들을 수정할 수 없습니다 의미 상수입니다. 그러나 단지 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

어느 쪽을 사용해야합니까? 필요에 맞는 것을 사용하십시오. 컴파일 타임 상수가 필요한 상황에서 사용할 수있는 컴파일 타임 상수가 있는지 확인 하시겠습니까? 런타임에 수행 된 계산으로 초기화 할 수 있습니까? 기타.


답변

여기에는 차이가 없지만 생성자가있는 형식이있을 때 중요합니다.

struct S {
    constexpr S(int);
};

const S s0(0);
constexpr S s1(1);

s0상수이지만 컴파일 타임에 초기화되지는 않습니다. s1로 표시 constexpr되므로 상수이며 S의 생성자도 표시 되므로constexpr 있으므로 컴파일 타임에 초기화됩니다.

대부분 런타임에 초기화하는 데 시간이 많이 걸리고 컴파일러로 작업을 푸시하려고 할 때 중요합니다.이 작업은 시간이 많이 걸리지 만 컴파일 된 프로그램의 실행 시간을 늦추지는 않습니다.


답변

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 변수”는 다음 두 가지 이유로 매우 일반적입니다.

  1. C ++ 98에는 constexpr이 없었으므로 사람들은 const을 사용했습니다 .
  2. 상수 표현식은 아니지만 (컴파일 타임에 값을 알 수없는) 변수 “목록 변수”는 초기화 후에 값을 변경하지 않는 것이 그 자체로 널리 유용합니다.

참조 : Stroustrup의 “프로그래밍 : C ++을 사용한 원리 및 실습”