次の定義に違いはありますか?
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
はコンパイル時の定数です。 shallコンパイル時に初期化されます。 PI1
は、コンパイル時または実行時に初期化できます。さらに、コンパイル時定数を必要とするコンテキストでonlyPI2
を使用できます。例えば:
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オブジェクトはコンパイル時に既知の値で初期化する必要がないため、constはconstexprと同じ保証を提供しないことに注意してください。
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ですが、すべてのconstオブジェクトが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++は2番目の形式の定数(a 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変数」は、次の2つの理由で非常に一般的です。
参照:Stroustrupによる「プログラミング:C++を使用した原則と実践」