C++20 の constexpr と consteval 関数

C++20 では、constexpr よりパワフルになりました。さらに、consteval があります constexpr によく似た C++20 の関数 関数。

最初に、私が最も驚いた C++20 の機能について説明しましょう。

constexpr 標準テンプレート ライブラリのコンテナとアルゴリズム

C++20 は constexpr をサポートします コンテナ std::vector そして std::string 、ここで constexpr 両方のコンテナーのメンバー関数をコンパイル時に適用できることを意味します。さらに、
Standard Template Library の 100 以上の古典的なアルゴリズムが constexpr として宣言されています。 .したがって、std::vector を並べ替えることができます コンパイル時の int の数。

これが何を意味するか見てみましょう:

// constexprVector.cpp

#include <algorithm>
#include <iostream>
#include <vector>

constexpr int maxElement() {
 std::vector myVec = {1, 2, 4, 3}; // (1)
 std::sort(myVec.begin(), myVec.end());
 return myVec.back();
}
int main() {

 std::cout << '\n';

 constexpr int maxValue = maxElement();
 std::cout << "maxValue: " << maxValue << '\n';

 constexpr int maxValue2 = [] {
 std::vector myVec = {1, 2, 4, 3}; // (2)
 std::sort(myVec.begin(), myVec.end()) ;
 return myVec.back();
 }(); 

 std::cout << "maxValue2: " << maxValue2 << '\n';

 std::cout << '\n';

}

2 つのコンテナ std::vector (行 (1) と (2)) はコンパイル時に constexpr を使用してソートされます -宣言された関数。最初のケースでは、関数 maxElement vector myVec の最後の要素を返します 、その最大値です。 2 番目のケースでは、 constexpr. と宣言された、すぐに呼び出されるラムダを使用します。 プログラムの出力は次のとおりです。

constexpr の重要なアイデア コンテナーは一時的な割り当てです。

一時的な割り当て

一時的な割り当てとは、コンパイル時に割り当てられたメモリもコンパイル時に解放する必要があることを意味します。その結果、コンパイラは constexpr で割り当てと解放の不一致を検出できます。 関数。次の例では、一時的な割り当てを適用しています。

// transientAllocation.cpp

#include <memory>

constexpr auto correctRelease() { 
 auto* p = new int[2020];
 delete [] p;
 return 2020;
}

constexpr auto forgottenRelease() { // (1)
 auto* p = new int[2020]; 
 return 2020;
}

constexpr auto falseRelease() { // (3)
 auto* p = new int[2020];
 delete p;  // (2)
 return 2020;
}

int main() {

 constexpr int res1 = correctRelease();
 constexpr int res2 = forgottenRelease();
 constexpr int res3 = falseRelease();

}

小さなプログラムには 2 つの重大な問題があります。まず、constexpr のメモリ 関数 forgottenRelease (行 (1)) は解放されません。次に、constexpr の非配列解放 (3 行目) 関数 falseRelease ((3)行目)が配列の割り当てと一致しません。その結果、コンパイルは失敗します。

C++20 では consteval になりました contexpr によく似た関数 関数。

consteval 関数

多くの場合、開発者は constexpr が 関数は実行時またはコンパイル時に実行されます。次のコード スニペットを考えてみましょう。

constexpr int constexprFunction(int arg) {
 return arg * arg;
}

static_assert(constexprFunction(10) == 100); // (1)
int arrayNewWithConstExpressiomFunction[constexprFunction(100)]; // (2)
constexpr int prod = constexprFunction(100); // (3)

int a = 100;
int runTime = constexprFunction(a); // (4)

int runTimeOrCompiletime = constexprFunction(100); // (5)

constexprFunction その名前が示すように、constexpr 関数。

<オール>
  • constexpr で使用する場合、constexpr 関数はコンパイル時に実行する必要があります。 コンテキストまたは結果はコンパイル時に要求されます。行 (1) と行 (2) は constexpr です コンテキスト。反対に、(3) 行目では constexprFuncion の関数実行が必要です。 コンパイル時
  • コール constexprFunction(a)  (4 行目) a は定数式ではないため、実行時に実行する必要があります。
  • 5 行目は興味深いケースです。関数の実行に要件はありません。したがって、constexprFunction(100) の呼び出し (5 行目) は、実行時またはコンパイル時に実行できます。 C++ 標準の観点からは、どちらでも問題ありません。
  • constexpr とは対照的 関数、consteval 関数はコンパイル時にのみ実行できます。

    consteval いわゆる即時関数を作成します。

    consteval int sqr(int n) {
     return n * n;
    }
    

    即時関数を呼び出すたびに、コンパイル時の定数が作成されます。 consteval 割り当てまたは割り当て解除を行うデストラクタまたは関数には適用できません。 consteval 関数は constexpr です 関数は暗黙的にインラインであり、constexpr の要件を満たす必要があります 関数。

    constexpr の要件 C++14 の関数、したがって consteval 機能は次のとおりです:

    • A consteval (constexpr )できます
      • 条件付きジャンプ命令またはループ命令がある
      • 複数の指示がある
      • constexpr 関数を呼び出します。 consteval 関数は constexpr のみを呼び出すことができます 機能しますが、その逆ではありません
      • 定数式で初期化する必要がある変数として、基本的なデータ型を使用します。
    • A consteval (constexpr ) 関数はできません
      • 静的または thread_localを持つ データ。
      • try ブロックも goto 命令もありません。
      • consteval 以外の呼び出しまたは使用 関数または非 constexpr データ。

    consteval という興味深い使用例が 1 つあります。 可能にします。コンパイル時にローカルの非定数変数を初期化できます。

    // compileTimeInitializationLocal.cpp
    
    consteval auto doubleMe(auto val) {
     return 2 * val;
    }
    
    int main() {
    
    auto res = doubleMe(1010); // (1)
    ++res; // 2021 (2)
    
    }
    

    ローカル res コンパイル時に初期化され (1 行目)、実行時に変更されます (2 行目)。逆に、関数 doubleMe の場合 constexpr として宣言されています 、実行時に実行できます。

    次は?

    テンプレートを使用した新しいトピック ブロックの設計に入る前に、次の投稿で C++17 機能 constexpr if. constexpr if  を紹介したいと思います。 条件付きでソース コードをコンパイルできるようにし、コンパイル時の便利なトリックにも使用できます。


    No