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 は定数式ではないため、実行時に実行する必要があります。
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
を紹介したいと思います。 条件付きでソース コードをコンパイルできるようにし、コンパイル時の便利なトリックにも使用できます。