constexpr if

今日の投稿では、非常に興味深い C++17 機能を紹介したいと思います:constexpr if. constexpr if 条件付きでソース コードをコンパイルできるようにし、コンパイル時の便利なトリックにも使用できます。

constexpr if の紹介

template <typename T>
auto getValue(T t) {
 if constexpr (std::is_pointer_v<T>)  // (1)
 return *t; // deduces return type to int for T = int*
 else // (2)
 return t; // deduces return type to int for T = int
}

コード スニペットは、 constexpr if に関する 1 つの興味深い事実を示しています。 :constexpr if といいますが 、 if constexpr として使用されます :if constexpr (std::is_pointer_v<T> ).

If T がポインタの場合、(1) 行の if 分岐がコンパイルされます。そうでない場合は、(2) 行の else 分岐。重要な点は 2 つあります。関数 getValue 2 つの異なる戻り値の型と if の両方の分岐があります ステートメントは有効でなければなりません。

constexpr の式は、コンパイル時の述語でなければなりません。コンパイル時の述語は、ブール値を返し、コンパイル時に実行される関数です。コード スニペットでは、type-traits ライブラリの関数を使用しました。あるいは、C++20 では概念を使用できます。概念 std::integral:を使用した同等の例を次に示します。

template <typename T>
auto get_value(T t) {
 if constexpr (std::integral<T>) // (1)
 return *t; // deduces return type to int for T = int*
 else // (2)
 return t; // deduces return type to int for T = int
}

なるほど、2 つのコード スニペットはそれほど印象的ではありません。テンプレートのメタプログラミングを続けましょう。

constexpr if に感謝 、テンプレートのメタプログラミングは、多くの場合、読み書きが容易です。

constexpr if によるテンプレート メタプログラミング

メタプログラミングは、プログラムのプログラミングです。 C++ は、コンパイル時にメタプログラミングを適用します。テンプレート メタプログラミングで C++98 に始まり、型特性ライブラリを使用して C++11 で形式化され、C++11 以降、着実に改善されています。

テンプレート メタプログラミングの「Hello World」:数値の階乗の計算:

// factorial.cpp

#include <iostream>

template <int N> // (2)
struct Factorial{
 static int const value = N * Factorial<N-1>::value;
};

template <> // (3)
struct Factorial<1>{
 static int const value = 1;
};

int main(){
 
 std::cout << '\n';
 
 std::cout << "Factorial<5>::value: " << Factorial<5>::value << '\n'; // (1)
 std::cout << "Factorial<10>::value: " << Factorial<10>::value << '\n'; // (4)
 
 std::cout << '\n';

}

コール factorial<5>::value (行 1) は、基本テンプレートまたは一般テンプレートのインスタンス化を引き起こします (行 2)。このインスタンス化の間、Factorial<4>::value インスタンス化されます。この再帰は、完全に特殊化されたクラス テンプレート Factorial<1> の場合に終了します。 開始します (3 行目)。

テンプレートのメタプログラミングについて詳しく知りたい場合は、以前の投稿をお読みください:

<オール>
  • テンプレート メタプログラミング - すべての始まり
  • テンプレート メタプログラミング - 仕組み
  • テンプレート メタプログラミング - ハイブリッド プログラミング
  • constexpr i を使ってプログラムを書き直してみましょう f:

    // factorialConstexprIf.cpp
    
    template <int N> // (1)
    struct Factorial{
     static int const value = N * Factorial<N-1>::value;
    };
    
    template <> // (2)
    struct Factorial<1>{
     static int const value = 1;
    };
    
    template <int N> // (3)
    constexpr int factorial() {
     if constexpr (N >= 2) 
     return N * factorial<N-1>();
     else 
     return N;
    }
    
    int main(){
     
     static_assert(Factorial<5>::value == factorial<5>()); // (4) 
     static_assert(Factorial<10>::value == factorial<10>()); // (4)
    
    }
    

    Factorial のプライマリ テンプレート (1行目) constexpr の if 条件になります 関数 factorial (3 行目)、および Factorial の完全な特殊化 for 1 (2 行目) は constexpr の else ケースになります。 関数の階乗 (3 行目)。もちろん、クラス テンプレート Factorial そして constexpr 関数 factorial 同じ結果を返し、コンパイル時に実行されます (4 行目)。簡潔にするために、私は constexpr if を使用する constexpr 関数を好みます 通常の機能とほぼ同じように読めるからです。

    もう一度やりましょう。悪名高いフィボナッチ関数ベースのテンプレート メタプログラミング (Fibonacci ) と constexpr if (fibonacci).

    // fibonacciConstexprIf.cpp
    
    template<int N>
    constexpr int fibonacci()
    {
     if constexpr (N>=2)
     return fibonacci<N-1>() + fibonacci<N-2>();
     else
     return N;
    }
    
    template <int N> // (1) 
    struct Fibonacci{
     static int const value = Fibonacci<N-1>::value + Fibonacci<N-2>::value;
    };
    
    template <> // (2) 
    struct Fibonacci<1>{
     static int const value = 1;
    };
    
    template <> // (3) 
    struct Fibonacci<0>{
     static int const value = 0;
    };
    
    int main() {
    
     static_assert(fibonacci<7>() == 13);
     static_assert(fibonacci<7>() == Fibonacci<7>::value);
     
    }
    

    constexpr 関数 fibonacci 読むのは簡単です。機能全体が 1 つの関数本体にあります。対照的に、テンプレート メタプログラム Fibonacci 3 つのクラスが必要です。プライマリ テンプレート (1 行目) と値 1 と 0 の 2 つの完全な特殊化 (2 行目と 3 行目)。

    メンター プログラム「Fundamentals for C++ Professionals」の詳細

    https://www.modernescpp.org/ で新しいメンタリング用のプラットフォームを作成しました。 28 の各レッスンをスキップできます。また、移動セマンティクスと完全転送に関する 6 番目のレッスンについては、「私のメンタリング プログラムに関する詳細情報「C++ プロフェッショナル向けの基礎」」という記事で紹介しました。メンタリング プログラムを開始する前の次のステップは次のとおりです。

    • 3 月の初め :メンタリング プログラムに関するオンライン説明会です。質問もできます
    • 3 月中旬: メンタリング プログラムの登録が始まります
    • 4 月: メンタリング プログラムの登録が終了し、メンタリング プログラムが開始されます

    最新情報を入手したい場合は、このメール アドレスはスパムロボットから保護されています。表示するには JavaScript を有効にする必要があります。 「メンタリング」をテーマに。さらに情報が必要な場合は、私に電子メールを書いてください。

    次は?

    テンプレートは強力なツールであるため、新しいデザインの選択肢を提供します。次回の投稿では、静的ポリモーフィズムと動的ポリモーフィズムについて書きます。