テンプレートの特殊化

テンプレートは、クラスまたは関数のファミリの動作を定義します。多くの場合、特殊なタイプまたは非タイプを特別に扱う必要があります。この使用例をサポートするために、テンプレートを特殊化できます。

テンプレートの特殊化の一般的な考え方からこの投稿を始めましょう。次の投稿では、詳細に集中します。

テンプレートの専門化

テンプレートは、クラスと関数のファミリの動作を定義します。多くの場合、特殊なタイプまたは非タイプを特別に扱う必要があります。したがって、テンプレートを完全に特化することができます。

クラス テンプレートは、部分的に特化することもできます。一般テンプレートまたは基本テンプレートは、部分的または完全に特殊化されたテンプレートと共存できます。特殊化のメンバー関数と属性は、プライマリ テンプレートのものと同じである必要はありません。コンパイラは、部分的に特化されたテンプレートよりも完全に特化されたテンプレートを優先し、プライマリ テンプレートよりも部分的に特化されたテンプレートを優先します。

次の例は、私の言葉を明確にするはずです。

template <typename T, int Line, int Column> // (1)
class Matrix;

template <typename T> // (2)
class Matrix<T, 3, 3>{};

template <> // (3)
class Matrix<int, 3, 3>{};

  • プライマリ テンプレート

行 1 は、プライマリまたは一般的なテンプレートです。プライマリ テンプレートは、部分的または完全に特殊化されたテンプレートの前に宣言する必要があります。プライマリ テンプレートが不要な場合は、1 行目のような宣言で問題ありません。

  • 部分専門化

2 行目は、部分的な特殊化が続きます。部分的な特殊化をサポートするのは、クラス テンプレートのみです。部分的な特殊化には、テンプレート パラメーターと明示的に指定されたテンプレート引数があります。具体的なケースでは, class Matrix<T, 3, 3> T はテンプレート パラメータで、数字はテンプレート引数です。

  • フルスペシャライゼーション

行 3 は完全な特殊化です。 Full は、すべてのテンプレート引数が指定され、テンプレート パラメーター リストが空であることを意味します: template <> 3 行目

部分的な専門化と完全な専門化

部分的および完全な特殊化をよりよく理解するために、視覚的な説明を提示したいと思います。ご存じかもしれませんが、私は数学を勉強していて、解かなければならない線形連立方程式がたくさんありました。

テンプレート パラメーターの n 次元空間について考えてみましょう。部分特殊化は n 次元空間の部分空間であり、完全特殊化は n 次元空間の点です。

ここで、視覚的な説明をクラス テンプレート Matrix に適用します。 そしてその部分的および完全な専門化。プライマリ テンプレート (1 行目) では、テンプレート パラメーターとして型を選択し、2 つの int を選択できます。 非型テンプレート パラメータとしての値。 2行目の部分特化の場合は型しか選べません。これは、3 次元空間が線に縮小されることを意味します。プライマリ テンプレートの部分的な特殊化 Matrix したがって、 は 3 次元空間の部分空間です。完全な特殊化 (3 行目) は、3 次元空間内の点を表します。

テンプレートを呼び出すとどうなりますか?

プライマリ、部分、および完全な専門化の使用

クラス Matrix の次の特殊化を思い出してください。

template <typename T, int Line, int Column> // (1)
class Matrix;

template <typename T> // (2)
class Matrix<T, 3, 3>{};

template <> // (3)
class Matrix<int, 3, 3>{};

問題は、Matrix をインスタンス化するとどうなるかです。 さまざまなテンプレート引数に対して?ここに 3 つのインスタンス化があり、コンパイラが何を作成するかがわかります。

Matrix<int, 3, 3> m1; // class Matrix<int, 3, 3>

Matrix<double, 3, 3> m2; // class Matrix<T, 3, 3> 

Matrix<std::string, 4, 3> m3; // class Matrix<T, Line, Column> => ERROR

m1 は完全な特殊化を使用し、m2 は部分的な特殊化を使用し、m3 はプライマリ テンプレートを使用しますが、定義がないためにエラーが発生します。

このプロセスを理解するには、いくつかのルールを覚えておく必要があります。以下は、特にクラス テンプレートの部分的な特殊化に適用される規則です。

テンプレート パラメータとテンプレート引数の間の依存関係

  • 明示的に指定されたテンプレート引数の数と順序 (<T, 3, 3> ) は、テンプレート パラメーター リスト (<typename T, int Line, int Column>) の番号とシーケンスと一致する必要があります。 ) の主要なテンプレートです。
  • テンプレート パラメータにデフォルトを使用する場合、テンプレート引数を指定する必要はありません。テンプレート パラメータのデフォルトを受け入れるのは、プライマリ テンプレートのみです。

有効な部分専門化

  • テンプレートのインスタンス化引数が (Matrix<double, 3, 3> の場合、コンパイラは部分的な特殊化を選択します。 ) は、部分的な特殊化 (Matrix<T, 3, 3>) のテンプレート引数のサブセットです。 ).

選択されたテンプレートの専門化

<オール>
  • コンパイラは特殊化を 1 つだけ検出します。コンパイラはこの特殊化を使用します。
  • コンパイラが複数の特殊化を検出しました。コンパイラは、最も特殊化されたものを使用します。このプロセスが複数の特殊化で終了した場合、コンパイラはエラーをスローします。
  • コンパイラは特殊化を検出しません。主要な専門分野を使用します。
  • さて、私が答えなければならない質問が1つ残っています。テンプレートが A 別のテンプレートよりも特化したテンプレートです B .これは私の非公式な定義です。

    テンプレート A はテンプレート B よりも専門的です:

    • テンプレート B は、テンプレート A が受け入れることができるすべての引数を受け入れることができます。
    • テンプレート B は、テンプレート A が受け入れられない引数を受け入れることができます。

    より正式なものにしたい場合は、cppreference.com/partial_specialization にアクセスして、半順序付けに関するサブセクションに進んでください。

    次は?

    この投稿では、テンプレートの特殊化に関する基本を説明する必要がありますが、いつものように、C++ での詳細が記載されています。たとえば、部分的または完全な特殊化はコンパイル時のように動作し、クラスまたは関数テンプレートの完全な特殊化は通常のクラスまたは関数と非常に似ています。