constとconstexprの違いメモ
C++11にて新しく導入された識別子、constexprについて勉強したメモです。なお、constexprはC++14にて大幅に改善され、このブログはC++14上で実験をして書いています。
const変数とconstexpr変数
まずconst変数とは、定数、つまり定義後に変更することのできない値です。
const int ci = 0; ci = 5; // Error! const変数の変更は不可
constexpr変数は定数であることに加えて、コンパイル時に既知の値を保持する値です。const変数が実行時に評価されるのに対してconstexpr変数はコンパイル時に評価されます。つまり、constexprを使用すれば、実行時の処理が少なくなるため高速化を実現できますし、メモリ使用量も減らすことができます。(コンパイル時間は長くなります)
constexpr int cei = 0; // コンパイル時に値が初期化される cei = 5; // Error! constexpr変数の変更は不可
int i = 0; const int a = i; // OK constexpr int b = i; // iはコンパイル時に既知の値でないためコンパイルエラー
const関数とconstexpr関数
constはメンバ関数を修飾することができます。その場合、その関数はその関数の呼び出し元であるオブジェクトを変更しないことを保証します。
constexprはメンバ関数に限らず一般の関数やコンストラクタなどを修飾することができます。その場合、constメンバ関数とは意味が異なり、その関数はできる限りコンパイル時に実行されます。「できる限り」というのが気持ち悪くもありますが、もし引数などがコンパイル時に不定だった場合、通常の関数と同様実行時に実行されます。
下記のコードをデバッグすると、bはコンパイル時に初期化されるため、ConstexprFunctionは実行時には1回(dの初期化時に)しか呼び出されていないことがわかります。
constexpr int ConstexprFunction(int i) { return i * 10; } int main() { // コンパイル時に実行される constexpr int a = 10; constexpr int b = ConstexprFunction(a); // 実行時に実行される int c = 10; int d = ConstexprFunction(c); }
ただし、constexpr関数が受け取れる値、返せる値はリテラル型(=コンパイル時に決定される値を保持できる型)に限定されます。
まとめ
constexprを使うと、可能な時にはコンパイル時に処理を実行してくれるため、コードの実行速度向上やメモリ効率の向上を実現できます。また可能でない場面でも今までと同じように処理が実行時に走るだけです。constexprが利用可能な場面では積極的に使っていくのがよさそうです。