質問: C++11にて導入されたconstexprについて、従来のconst修飾子との違いを教えて下さい。 一般的な利用においては同様に振舞っているように見えますが、constとconstexprで動作に差が出る例も示していただけると幸いです。
回答: C++11におけるconstexprは特定の条件を満たす変数をコンパイル時定数にし、特定の条件を満たす関数とコンストラクタについてその処理を実行時ではなくコンパイル時に行うことを明示するキーワードです。 const変数は基本的に初期化されれば以降変更されない変数です。また、クラスのconstメンバ関数は基本的にメンバ変数に変更を加えないメンバ関数です。さらに、const TとTは型として区別されます。 このように、**constexprとconstはそれぞれで使用目的が異なり、まったくの別物です。** ただし、constexpr変数はconst修飾されるので、質問者の言う"一般的な利用"がたまたまconstexpr変数になる条件を満たした既存のコードのconst変数のconst修飾をconstexpr修飾に置き換えることを指すのであれば、一見同じに見えるかもしれません。しかしながら**変数をconst修飾する場合とconstexpr修飾する場合でプログラムの動作が基本的に異なることは留意すべきです**(たまたまコンパイラの最適化などによって同じ動作になることはありえます)。 constexprを用いた場合と用いない場合のプログラムの分かりやすい動作の差としては、用いた場合は基本的にコンパイル時に処理が行われるので、用いない場合と比べてコンパイル時の計算量は増えて、実行時の計算量は減るというのが挙げられます。 constexpr関数について constexpr修飾された関数はinline修飾されます。 constexpr指定してコンパイル時に実行できる関数は大雑把には以下の条件を満たす必要があります。 * 仮想関数ではない * forやwhileなどのループを使わない * ifやswitchを使わない * ローカル変数の宣言を含まない * return文が必ずひとつ、そしてひとつだけ存在する * 引数と返り値はリテラル型である ゆえに複雑な処理をするためには、ループではなく再帰を使い、条件分岐には?演算子を使い、ローカル変数の代わりに仮引数変数を使います。こうすると、結果的に関数型言語の作法とよく似た書き方になります。 ``` // 階乗を求めるC++11におけるconstexpr関数 constexpr unsigned int factorial(unsigned int x) { return x == 0 ? 1 : factorial(x - 1) * x; } ``` ちなみにC++14におけるconstexpr関数では上記の制限が大幅に緩和されたので次のように書けます。 ``` // 階乗を求めるC++14におけるconstexpr関数 constexpr unsigned int factorial(unsigned int x) { unsigned int result = 1; while(x) { result = result * x--; } return result; } ``` constexprについての日本語の資料は「constexpr 中3女子」でググればたくさん出てくるので活用すれば良いでしょう。 参考 * cppreference.com: constexpr specifier (since C++11) * 中3女子でもわかる constexpr