1929


C++11にて導入されたconstexprについて、従来のconst修飾子との違いを教えて下さい。

一般的な利用においては同様に振舞っているように見えますが、constとconstexprで動作に差が出る例も示していただけると幸いです。


CC BY-SA 3.0
2014-12-17T12:22:39.497
1920
2014-12-18T08:06:03.437
197
question
c++ c++11
constとconstexprの違い


この↓訳文でいかがですか？  
<http://www32.ocn.ne.jp/~ons/text/CPP0xFAQ.html.ja#constexpr>

constexpr はコンパイル時定数として評価されるもの、const は実行時に読み取り専用として扱われるもの (なので、const
宣言されていても定数であるとは限らない。そのスコープで書き込みされないというだけ。ついでに言うと、mutable 指定されたメンバに対するアクセスは
const 性の担保の対象外になります)。

また、constexpr として定義されたオブジェクトは const 性を持つと言っても概ね問題ないと思いますが、逆は真ではありません。

他にマニアックな例としては、コンストラクタの戻り値を constexpr と書くことはできますが、const と書くことはできません、とか。

[code]

    class A {
            // こうは書ける。
            constexpr A() { }
    };
    
    class B {
            // こうは書けない (書けたとしても意味はないけれど)。
            const B() { }
    };
    
[/code]


CC BY-SA 3.0
2014-12-17T13:26:35.313
1929
2014-12-17T13:26:35.313
4665
1920
answer


constexprは従来の#defineを置き換えとして機能するものになり、constではできなかったコンパイル時に実行できる関数などを定義できるようになっている点が大きな違いです。
従来のマクロ関数とは異なり、名前空間に属したり、クラスのメンバ関数として記述できたりします。
ただし定数として使うときはconstみたく実行時に値が変わるような使い方ができません。 以下の英文サイトを参考にしましたが、間違っていたらすみません。
<http://en.cppreference.com/w/cpp/language/constexpr>


CC BY-SA 3.0
2014-12-17T13:46:38.170
1931
2014-12-17T13:46:38.170
3103
1920
answer


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文が必ずひとつ、そしてひとつだけ存在する
  * 引数と返り値はリテラル型である

ゆえに複雑な処理をするためには、ループではなく再帰を使い、条件分岐には?演算子を使い、ローカル変数の代わりに仮引数変数を使います。こうすると、結果的に関数型言語の作法とよく似た書き方になります。

[code]

    // 階乗を求めるC++11におけるconstexpr関数
    constexpr unsigned int factorial(unsigned int x) {
        return x == 0 ? 1 : factorial(x - 1) * x;
    }
    
[/code]

ちなみにC++14におけるconstexpr関数では上記の制限が大幅に緩和されたので次のように書けます。

[code]

    // 階乗を求めるC++14におけるconstexpr関数
    constexpr unsigned int factorial(unsigned int x) {
        unsigned int result = 1;
        while(x) { result = result * x--; }
        return result;
    }
    
[/code]

constexprについての日本語の資料は「constexpr 中3女子」でググればたくさん出てくるので活用すれば良いでしょう。

## 参考

  * [cppreference.com: constexpr specifier (since C++11)](http://en.cppreference.com/w/cpp/language/constexpr)
  * [中３女子でもわかる constexpr](http://www.slideshare.net/GenyaMurakami/constexpr-10458089)


CC BY-SA 3.0
2014-12-18T08:06:03.437
2011
2014-12-18T08:06:03.437
4548
1920
answer