C++ によるテンプレートの理解

いわゆるテンプレートは実際には一般的な関数またはクラスを作成しますが、クラスの内部型や関数の仮引数の型は指定されず、仮想型で表現されます。


たとえば、Add 加算関数を実装したい場合、さまざまな型に対して関数を複数回オーバーロードする必要がありますか? 実際、これらの複数の関数実装の基本原理は同じですが、型が異なります。この状況に基づいたテンプレート。

f92327ff0540447da917b336a1fb68b5.jpeg


 

 関数テンプレート

関数テンプレートは、型に依存しない関数ファミリーを表します。使用すると、パラメーターが仮想化され、関数の特定の型バージョンが実際のパラメーター型に基づいて生成されます。


フォーマット要件

関数を定義する前に、次の行を記述します: template<typename T1, typename T2,..., typename Tn>. ここの typename を class に置き換えても問題ありません。関数定義は通常どおりに記述されますが、元のインスタンス化タイプが仮想化タイプ (つまり、前の行の T1、T2...) に置き換えられる点が異なります。


例 関数テンプレートの追加

template<class T>
T Add(const T& a, const T& b)
{
	return a + b;
}

ここでは全体として 1 つのタイプのみを置き換える必要があるため、テンプレート パラメーターに T を指定するだけです。

ただし、型も統一する必要があります。

int main()
{
	double sum = Add(1.2, 1);
	cout << sum << endl;
}

main 関数が次のように記述されている場合、「パラメーター リストに一致する関数テンプレート "Add" がありません」というエラーが報告されます。

これに対する解決策もあります:関数テンプレートのインスタンス化(実際には型マッチングも行います)


関数テンプレートのインスタンス化 

関数テンプレートのインスタンス化は、実際には関数パラメータをインスタンス化されたテンプレート関数の 1 つのパラメータに統合することです。

暗黙的なインスタンス化

つまり、コンパイラーにパラメーターの型を直接伝えず、コンパイラーが生成するシミュレーション ボード関数内で一致するものを見つけさせます。

template<class T>
T Add(const T& a, const T& b)
{
	return a + b;
}
int main()
{
	double sum = Add(1.2, (double)1);//强制类型转换
	cout << sum << endl;
}

実際、これは暗黙的な変換です。

実際、テンプレート関数を作成すると、次の 2 つのコンパイルが発生します。

  1. インスタンス化する前に、テンプレート コード自体をチェックして、構文が正しいかどうかを確認してください。
  2. インスタンス化中に、テンプレート コードがチェックされ、すべての呼び出しが有効かどうかが確認されます。

関数テンプレートが生成されると、コンパイラ自体がさまざまなタイプの複数のオーバーロード関数を生成するのと同じになります。関数テンプレートを呼び出すと、コンパイラは、生成されたすべてのオーバーロード関数の中から最も一致するものを見つけて呼び出すことができます。

明示的なインスタンス化 

表示インスタンス化の特徴は、関数名の後に <type> を追加することであり、Type は関数を呼び出すときの特定の型です。

int main()
{
	double sum = Add<double>(1.2,1);
	cout << sum << endl;
}

これは、呼び出される関数のパラメーターの型が double であることをコンパイラーに直接伝えることと同じであるため、これは明示的なインスタンス化です。


関数テンプレートとテンプレート関数 

この基本的な概念と、関数テンプレートとテンプレート関数の関係について説明します。

まず第一に、それらはまったく同じものではありません。

関数テンプレートはテンプレートであり、関数ファミリーと同等であり、ファミリーのメンバーはテンプレート関数 (インスタンス化された関数) です。通常、関数テンプレートを作成すると、コンパイラがユーザーが使用できるさまざまなタイプのテンプレート関数を自動的に生成します。 . .

 


クラステンプレート

クラス テンプレートは、実際には上記の関数テンプレートとほぼ同じです。

template<typename T, int N>
class Test
{
public:
    Test()
        :_arr(new T[N])
    {
        for (int i = 0; i < N; i++)
            _arr[i] = i+0.5;
    }
    ~Test()
    {
        delete[]_arr;
    }

private:
    T* _arr;
};

このテンプレートの機能は、単に配列を作成して初期化を完了することです。ここでは 2 つのテンプレート パラメーターが使用されているため、次のように記述されます: template<typename T, int N>、int N は配列のサイズなので、次のように記述します。 int 型を直接指定します。N はパラメータの 1 つです。

ただし、関数テンプレートと比較すると、クラス テンプレートには暗黙的なインスタンス化がなく、オブジェクトは明示的なインスタンス化によってのみ作成できます。

int main()
{
    Test<double,5> arr;
}

呼び出しを明示的にインスタンス化しない場合、コンパイラー自体が特定のテンプレート関数を識別できないためです。


クラス テンプレート内の関数がクラスの外部で定義されている場合、テンプレート パラメーター リストを追加する必要があります。

template<typename T, int N>
class Test
{
public:
    Test();
    ~Test()
    {
        delete[]_arr;
    }

private:
    T* _arr;
};

template<typename T, int N>
Test<T, N>::Test()
:_arr(new T[N])
{
    for (int i = 0; i < N; i++)
        _arr[i] = i + 0.5;
}

テンプレートパラメータリストを追加するだけでなく、クラスタイプも追加する必要があります。テンプレートクラスのタイプは、一般のクラスのタイプとは異なります。テンプレートクラスのタイプ = クラス名 + <T1 , T2...>. それに比べて、一般的なクラスの場合、クラス名は型です。

 

テンプレートパラメータ

さて、テンプレートパラメータについて話しましょう. 事前に宣言しておきますが、テンプレートパラメータは関数パラメータやクラスパラメータではなく、分離する必要があります。

テンプレート パラメータの仮パラメータは、テンプレート パラメータ リストの T です。上記のテンプレート クラスを例に取ると、2 つのテンプレート パラメータ T と N があります。仮パラメータを使用すると、実パラメータは double と 5 になります。



ご指導のための訪問を歓迎します。

203bdc7adca845edb657314c2a177355.jpeg

 

 

おすすめ

転載: blog.csdn.net/C_Rio/article/details/132087617