48374


constは値が変更できない変数でconstexprはこの機能を使用することで、コンパイル時に値が決定する定数、"コンパイル時に実行される関数"、"コンパイル時にリテラルとして振る舞うクラスを定義できる"

１、コンパイル時に実行される関数  
２、コンパイル時にリテラルとして振る舞うクラスを定義できる"  
３、visual studio 2017の環境下では#define NUMBER 5
と定義すると「constexprに変えたらどうですか？」みたいな提案のマークがでるのですがそうしたほうがいいのでしょうか？場合にもよると思うのですが教えてほしいです。

この三つの意味を教えてほしいです。

[code]

    //#define NUMBER 5
    constexpr auto NUMBER = 5;
    
    constexpr int num = 5;
    const int n = 5;
    
    int main() {
        _getch();
        return 0;
    }
    
[/code]


CC BY-SA 4.0
2018-09-13T14:19:14.170
48369
2018-09-14T00:38:29.197
2018-09-14T00:38:29.197
3060
question
c++
c++ constexpr型指定子の使い方とconstとの使い分けの方法


[c++](/questions/tagged/c%2b%2b "'c++' のタグが付いた質問を表示")
は実行時の性能を最重要視する言語なので、コンパイル時に処理できるものは可能な限りコンパイル時にやっておしまい！という風潮があります。 `constexpr`
は既にお書きのとおり、コンパイル時にできることはコンパイル時にやれという、プログラマからコンパイラへの指示です。

質問本文に挙げてある例は簡単すぎて違いが判らないので別の例を挙げながら説明を試みます。

`const` の意味

[c++](/questions/tagged/c%2b%2b "'c++' のタグが付いた質問を表示") の `const`
は決して定数ではありません。変更禁止という意味です。オイラ個人が誰かに教えるときは `readonly` と読み替えろと言っています。

[code]

    extern int getvalue();
    void func() {
        const int n=getvalue(); // good
        ++n; // error
    }
    
[/code]

この例で `n` は、コンパイル時点では値が不明です。 `const`
はコンパイル時定数ではないのでこの初期化は受け付けられます。いったん初期化したのちは変更禁止なのでインクリメントはコンパイル時エラーとなります。

`constexpr` の意味

コンパイル時に結果の値まで評価できる式や関数には `constexpr`
をつけることができます。その評価結果はコンパイル時定数として扱われます。評価できない場合はコンパイルエラーになります。式のほうはほぼ自明なんですが、関数に
`constexpr` をつけてよい状況はかなり限定されます。詳細はここでは略。

[code]

    constexpr int getvalue1() { return 3; }
    int array1[getvalue1()];
    
[/code]

この例では、コンパイル時に `constexpr` が評価できる結果 `int array1[3];` となり大域変数が正しく定義できます。

[code]

    const int getvalue2() { return 3; }
    int array2[getvalue2()];
    
[/code]

`const` にした場合、コンパイル時評価をしない・しなくてよいという指示にしか読まないという言語仕様なので、こちらはコンパイル時エラーとなります。

[code]

    template<int n> constexpr int sumto() { return n+sumto<n-1>(); }
    template<> constexpr int sumto<0>() { return 0; }
    int array3[sumto<10>()];
    
[/code]

こういう難しそうな関数でもコンパイル時定数＝リテラル、に評価できます。 `array3` の要素数がいくつになるのかは机上で検討してみてください。

> #define NUMBER 5 と定義するとconstexprに変えたらどうですか？

大前提としてプリプロセッサは大域字句的置換だと思い出してください。この例だとプリプロセッサは `NUMBER` という字句が現れると無造作に `5`
に置換してしまいます。

[code]

    #define NUMBER 5
    struct foo {
        int VALUE;
        int NUMBER;
        int COUNT;
    };
    
[/code]

なんてものを作ると `int 5;` に置換されコンパイルエラーになってしまいます。

[code]

    struct bar {
        static constexpr int NUMBER=5;
    };
    
[/code]

だと、こちらはスコープ規則に従うので `bar` の外では何の影響も及ぼさず安全です。

そういう意味で現代 [c](/questions/tagged/c "'c' のタグが付いた質問を表示") /
[c++](/questions/tagged/c%2b%2b "'c++' のタグが付いた質問を表示")
ではプリプロセッサを使うことは非推奨です。プリプロセッサでないと実現できない機能（端的には条件コンパイルっすね）以外はプリプロセッサを使わないように心がけたいです。


CC BY-SA 4.0
2018-09-14T00:24:04.200
48374
2018-09-14T00:24:04.200
8589
48369
answer