constexpr 変数 (C++11)
変数 宣言 時 に constexpr を 付加 する と、 constexpr 変数 という コンパイル 時定数 になり ます。 const を 付け た 変数 との 違い を 理解 する こと が ポイント です。 const の 場合 も 定数 と 呼ば れ ます が、 これ は 実行 時定数 で あり、 初期 値 の 部分 に 変数 や 関数 呼び出し が 含ま れ て いる とき、 その 評価 は 実行 時 に 行わ れ ます。 対し て、 constexpr の 場合 は コンパイル 時 に 評価 さ れ ます。 その ため、 コンパイル 時 に 評価 できる よう な 式 で ある 必要 が あり ます。
int f() { return 0; }
int main() {
const int v1 = f(); // OK。 f() は実行時に呼び出す
constexpr int v2 = f(); // コンパイルエラー。f()をコンパイル時に呼び出せない
int x = f();
const int v3 = x * 2; // OK。 xの値は実行時に分かれば良い
constexpr int v4 = x * 2; // コンパイル エラー。xの値がコンパイル時に必要
constexpr int y = 100;
const int v5 = y * 2; // OK。実行時に定数式を使うことに問題はない
constexpr int v6 = y * 2; // OK。yの値はコンパイル時に分かっている
}constexpr関数 (C++11/ 14)
関数 宣言 に constexpr を 付加 する と、 constexpr 関数 になり ます。constexpr 関数 は、 定数 式 の 中 から 呼び出す こと が できる ため、 constexpr 変数 の 初期化 時 に 使う こと が でき ます。 ただし 当然 ながら、 実 引数 について も、 コンパイル 時 に 評価 可能 な もの で なけれ ば なり ませ ん。
#include < iostream >
constexpr int f() {
return 10;
}
int main() {
constexpr int v1 = f(); // OK。 f()はコンパイル時に呼び出し可能
int v2 = f(); // OK。 定数式であることを必要としていない箇所でも呼び出し可能
// 以下、どちらもOK。
// これらは当然、実行時に行われる処理
std::cout << v1 << std::endl;
std::cout << v2 << std::endl;
}実行結果: 10 10
constexpr関数の制約
constexpr 関数 の 実装 について は、 C++11 の 時点 では 様々 な 制約 が あり、 C ++ 14 に なっ て 大きく 緩和 さ れ て い ます。 C++11 の 時点 では、 以下 の よう な 制約 が あり ます。
- 変数を宣言することはできない
- 非ローカル変数の値を書き換えることはできない
- 繰り返し (for、範囲 for、while、do-while) は使えない
- if 文、switch 文は使えない
- 戻り値をvoidにはできない
コンパイル 時 に 計算 できる こと は constexpr 関数 内 で 行う よう に すれ ば、 実行 効率 を 向上 さ せる こと が でき ます。
before (C++98/ 03)
#include < iostream >
#define SIZE_OF_ARRAY(array) (sizeof(array) / sizeof(array[0]))
static const int NUMBERS[] = { 459, -60, 6089, 487, 94, 2, -53987, };
bool findNumber( int n) {
for (int i = 0; i < SIZE_OF_ARRAY(NUMBERS); ++ i) {
if (NUMBERS[i] == n) { return true; }
}
return false;
}
int main() {
const bool found = findNumber(487);
std::cout << std::boolalpha << found << std::endl;
}NUMBERS は コンパイル 時点 で 確定 し て いる データ で あり、 探す 値 も コンパイル 時定数 です が、 実行 時 に 探索 を 行う 必要 が あり ます。
after (C++11)
C ++ 11 では、 constexpr を 使え ます が、 constexpr 関数 内 では、 変数 宣言、 for 文、 if 文 が 使え ない ため、 他 の 手段 で 代替 する 必要 が あり ます。 for 文 は 関数 を 再帰 的 に 呼び出す こと で 代替 し、 if 文 は 条件 演算子 で 代替 し ます。 また、 コンパイル 時 に 参照 できる よう に、 NUMBERS の 方 も constexpr 変数 に する 必要 が あり ます。


コメント