constexprの使い方
C++11以降で導入されたconstexprの便利な使い方
constexpr
はC++11で導入された指定子ですが、明示的にリテラル定数であることを宣言できます。const
と何が違うのかというと、const
はあくまでオブジェクトが変更できないことを宣言しているのみで、リテラル定数扱いとなるかどうかはコンパイラ任せです。
例えば、昨今のコンパイラの場合下記のようなコードはconst
でもconstexpr
でも同じリテラル定数として扱われたコードが生成されると思います
int normal_i = 1;
const int const_i = -2;
constexpr int constexpr_i = 3;
int main() {
return normal_i + const_i + constexpr_i;
}
実際、clang++
9.0.1でコンパイルした結果のアセンブリ出力は以下のようになります
movl normal_i(%rip), %eax
addl $-2, %eax # const_iの加算
addl $3, %eax # constexpr_iの加算
ただし、const
の場合、以下のようにリテラル定数でない結果で初期化した場合はリテラル定数として扱われません。対して、constexpr
はそのような初期化自体がコンパイル時にエラーとなるため、意図しない非リテラル化をコンパイル時に検出することが可能となります
int max(int x, int y) { return (x > y) ? x : y; }
int normal_i = 1;
const int const_i = max(-2, -3);
// constexpr int constexpr_i = max(0, 2); // Error!
constexpr int constexpr_i = 2;
int main() {
return normal_i + const_i + constexpr_i;
}
例えば、上記コードではコンパイル結果は以下のようになり、const_iの値を計算するのに、実際max関数が呼び出されていることがわかります
movl normal_i(%rip), %eax
addl _ZL7const_i(%rip), %eax
addl $2, %eax
ちなみに#define max(x, y) ((x > y) ? x : y)
とマクロにした場合は最初のコードと同じように最適化されます。
ではconstexpr
の初期化にはマクロしか使用できないのか?というとそうではなく、関数もconstexpr
宣言することでそれが可能となります
int max(int x, int y) { return (x > y) ? x : y; }
constexpr int constexpr_max(int x, int y) { return (x > y) ? x : y; }
int normal_i = 1;
const int const_i = max(-2, -3);
constexpr int constexpr_i = constexpr_max(0, 2); // OK!
実際はconstexpr
はconst
の意味を包含しているので、
constexpr int max(int x, int y) { return (x > y) ? x : y; }
とmax()
を宣言しておけばOKです。 (実際std::max()
はそのように宣言されています)
またconstexpr
によって、リテラル定数しか使用できないenum
定義でもconstexpr func()
を使用することが出来るようになります
constexpr int kParamOne = 1;
constexpr int kParamTwo = -2;
enum { kCoefMax = max(kParamOne, kParamTwo)};
最近のコメント