constexpr (C++)

キーワード constexpr が C++11 で導入され、C++14 で改良されました。 これは、constAnt 式を意味します。 const のように、変数にそれを適用することができます。コードが値をif変更しようとしたときにコンパイラ エラーが生成されます。 const とは異なり、constexpr は関数やクラス const のコンストラクターにも適用できます。 constexpr は値または戻り値が constant であることを示し、可能な場合はコンパイル時に計算されます。

constexpr 整数値は、テンプレート引数や配列の宣言など、const の整数値が必要な場所で使用できます。 実行時ではなくコンパイル時に値を計算すると、プログラムをより高速に実行して、使用するメモリを少なくするのに役立ちます。

コンパイル時の constant 計算の複雑さと、コンパイル時の潜在的な影響を制限するために、c++ 14 標準では、constant 式の型がリテラル型である必要があります。

構文

constexprliteral-typeidentifier=constant-expression;
constexprliteral-typeidentifier{constant-expression};
constexprliteral-typeidentifier(params);
constexprctor(params);

パラメーター

params
1つ以上のパラメーター。それぞれがリテラル型である必要があり、それ自体が constant 式でなければなりません。

戻り値

constexpr 変数または関数は、リテラル型を返す必要があります。

constexpr 変数

const 変数と constexpr 変数の間の主な if 違いは、const 変数の初期化を実行時まで遅らせることができることです。 constexpr 変数は、コンパイル時に初期化する必要があります。 すべての constexpr 変数は const です。

  • 変数がリテラル型で初期化されている場合は、constexpr で宣言できます。 初期化がconstコンストラクターによって実行forされる場合、constコンストラクターは constexpr として宣言する必要があります。

  • 参照は、両方の条件が満たされたときに constexpr として宣言できます。参照されるオブジェクトは、const ant 式によって初期化されます。また、初期化中に呼び出された暗黙の変換も const ant 式になります。

  • constexpr 変数または関数のすべての宣言は、constexpr指定if子を持っている必要があります。

constexpr float x = 42.0;
constexpr float y{108};
constexpr float z = exp(5, 3);
constexpr int i; // Error! Not initialized
int j = 0;
constexpr int k = j + 1; //Error! j not a constant expression

constexpr 関数

constexpr 関数は、使用側コードが必要とする場合に、戻り値をコンパイル時に計算できます。 コードを使用するには、コンパイル時に constexpr 変数を初期化するか、非型テンプレート引数を指定する必要があります。 引数が constexpr 値の場合、constexpr 関数はコンパイル時に constant を生成します。 非 constexpr 引数を使用して呼び出されたとき、または値がコンパイル時に必要でない場合には、正規関数のように、実行時に値を生成します。 (この 2 重の動作により、同じ関数の constexpr と非 constexpr のバージョンを記述する手間が省けます。)

constexpr 関数またはconstコンストラクターは暗黙的に inline です。

constexpr 関数には次の規則が適用されます:

  • constexpr 関数はリテラル型のみを受け入れて返す必要があります。

  • constexpr 関数は再帰的にすることができます。

  • fore C++20 であり、関数をconstexpr仮想にすることはできません。またconst、外側のクラスに仮想基底クラスがある場合と同様constexprに、ルクターを定義することはできません。 C++20 以降では、関数を constexpr 仮想にすることができます。 Visual Studio 2019 バージョン 16.10 以降のバージョンでは、y 以降のコンパイラ オプションを指定ifした場合に仮想関数が/std:c++20サポートconstexprされます。

  • 本体は = default または = delete として定義できます。

  • 本文には、goto ステートメントまたは try ブロックを含めることはできません。

  • constexpr ではないテンプレートの明示的な特殊化は constexpr として宣言できます:

  • constexpr テンプレートの明示的な特殊化は、constexpr である必要はありません:

Visual Studio 2017 以降の constexpr 関数には、次の規則が適用されます。

  • これには、if ステートメントと switch ステートメント、および、for、範囲ベース forwhile、および do-while を含むすべてのループ ステートメントを含めることができます。

  • ローカル変数宣言が含まれている場合がありますが、変数を初期化する必要があります。 リテラル型である必要があり、static またはスレッド ローカルにすることはできません。 ローカルで宣言された変数は、const である必要はなく、変化する可能性があります。

  • constexprstatic メンバー関数は、暗黙的 const に指定する必要はありません。

constexpr float exp(float x, int n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp(x * x, n / 2) :
        exp(x * x, (n - 1) / 2) * x;
}

ヒント

Visual Studio デバッガーでは、最適化されていないデバッグビルドをデバッグするときに、コンパイル時に constexpr 関数が評価されているかどうかを、その中にブレークポイントを配置することで判断できます。 ブレークポイントにヒットすると、実行時に関数が呼び出されます。 ヒットしなければ、コンパイル時に関数が呼び出されます。

extern constexpr

/Zc:externConstexpr コンパイラ オプションを指定すると、コンパイラで extern constexpr が使用され、宣言された変数に外部リンケージが適用されます。 Visual Studio の以前のバージョンでは、既定で、または /Zc:externConstexpr- が指定されている場合、extern キーワードが使用されている場合でも、Visual Studio によって constexpr 変数に内部リンケージが適用されます。 /Zc:externConstexpr オプションは、Visual Studio 2017 Update 15.6 から使用できます。既定ではオフになっています。 /permissive- オプションでは、/Zc:externConstexpr は有効になりません。

次の例は constexpr 変数、関数、およびユーザー定義の型を示します。 main() の最後のステートメントでは、コンパイル時に値が既知である必要はないため constexpr メンバー関数 GetValue() は実行時の呼び出しです。

// constexpr.cpp
// Compile with: cl /EHsc /W4 constexpr.cpp
#include <iostream>

using namespace std;

// Pass by value
constexpr float exp(float x, int n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp(x * x, n / 2) :
        exp(x * x, (n - 1) / 2) * x;
}

// Pass by reference
constexpr float exp2(const float& x, const int& n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp2(x * x, n / 2) :
        exp2(x * x, (n - 1) / 2) * x;
}

// Compile-time computation of array length
template<typename T, int N>
constexpr int length(const T(&)[N])
{
    return N;
}

// Recursive constexpr function
constexpr int fac(int n)
{
    return n == 1 ? 1 : n * fac(n - 1);
}

// User-defined type
class Foo
{
public:
    constexpr explicit Foo(int i) : _i(i) {}
    constexpr int GetValue() const
    {
        return _i;
    }
private:
    int _i;
};

int main()
{
    // foo is const:
    constexpr Foo foo(5);
    // foo = Foo(6); //Error!

    // Compile time:
    constexpr float x = exp(5, 3);
    constexpr float y { exp(2, 5) };
    constexpr int val = foo.GetValue();
    constexpr int f5 = fac(5);
    const int nums[] { 1, 2, 3, 4 };
    const int nums2[length(nums) * 2] { 1, 2, 3, 4, 5, 6, 7, 8 };

    // Run time:
    cout << "The value of foo is " << foo.GetValue() << endl;
}

必要条件

Visual Studio 2015 またはそれ以降。

関連項目

宣言と定義
const