テンプレートを理解する - 初心者
序文:
テンプレートとは何ですか?テンプレートでできることは何ですか?好奇心を持ってテンプレートを学習すれば、間違いなく大きな成果が得られます。
1. テンプレート
1.1 テンプレートとは
テンプレートは、パラメーター化されたポリモーフィズムをサポートする C++ ツールです。テンプレートを使用すると、ユーザーはクラスまたは関数の一般的なパターンを宣言できるため、クラスまたはパラメーター内の特定のデータ メンバーとメンバー関数の戻り値を任意の型にすることができます。
1.2 テンプレートの概念
テンプレートは、C++ プログラミング言語のパラメーターとして型を使用するプログラミングを指し、一般的なプログラミングをサポートします。 C++ 標準ライブラリは多くの便利な関数を提供しており、そのほとんどは STL や iostream などのテンプレートの概念を組み合わせています。
テンプレートは、型をパラメータ化するためのツールです。
通常、関数テンプレートとクラス テンプレートの 2 つの形式があります。
- 関数テンプレート: 異なるパラメータ型を持つ関数のみ。
- クラス テンプレート: メンバー変数とメンバー関数のみが異なる型を持つクラス用。
テンプレートでは、コンパイラは通常、型変換操作を実行しません。これは、変換に問題がある場合、コンパイラが責任を負うことになるためです。
1.3 テンプレートでできること
テンプレートを使用する目的は、プログラマが型に依存しないコードを記述できるようにすることです。
1.4 汎用テンプレート
汎用プログラミング: 型に依存しない汎用コードを記述することは、コードを再利用する手段です。テンプレートは汎用プログラミングの基礎です。
2. 関数テンプレート
関数テンプレートのコンパイル (2 回):
1: インスタンス化する前に、コード自体に構文エラーがないか確認します。
2: インスタンス化中に、テンプレート コードの呼び出しが正当かどうかを確認します。
2.1 関数テンプレートの概念と形式
コンセプト:
関数テンプレートは、型に依存しない関数のファミリーを表し、実際のパラメーターの型に基づいて関数の型固有のバージョンを生成するために使用される場合にパラメーター化されます。
フォーマット:
テンプレート
戻り値の型関数名(パラメータ リスト){}
ケースは次のとおりです。
template<typename T>
void Swap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
注: typename はテンプレート パラメータの定義に使用されるキーワードです。クラスも使用できます (
クラスの代わりに struct を使用できないことに注意してください)
2.2 関数テンプレートの原理
関数テンプレートはブループリントであり、関数そのものではありません。コンパイラが使用方法を使用して特定の種類の関数を生成するためのテンプレートです。
つまり、実際には、テンプレートは実行すべき反復的な処理をコンパイラに渡します。
ネットワークマップ:
コンパイラーのコンパイル段階では、テンプレート関数を使用するために、コンパイラーは、呼び出し用に渡された実際のパラメーターの型に基づいて、対応する型の関数を推定して生成する必要があります。例: double 型の関数テンプレートを使用する場合、コンパイラは実際のパラメーターの型の演繹を通じて T を double 型として決定し、double 型を特別に処理するコードを生成します。これは文字型にも当てはまります。
2.3 関数テンプレートのインスタンス化
関数テンプレートが異なる型のパラメーターとともに使用される場合、それは関数テンプレートのインスタンス化と呼ばれます。テンプレートパラメータのインスタンス化は、暗黙的なインスタンス化と明示的なインスタンス化に分けられます。
2.3.1 暗黙的なインスタンス化
暗黙的インスタンス化: 推定インスタンス化とも呼ばれ、関数パラメーターが渡され、テンプレート パラメーターの型が導出され、対応する関数が生成されます。 (実際のパラメータに基づいて、コンパイラにテンプレート パラメータの実際の型を推定させます)
2.3.2 明示的なインスタンス化
明示的なインスタンス化: 関数名の後の <> でテンプレート パラメーターの実際の型を指定します。
2.4 テンプレートパラメータのマッチング原則
1. 非テンプレート関数は、同じ名前の関数テンプレートと同時に存在でき、関数テンプレートは非テンプレート関数としてインスタンス化することもできます。
2. 非テンプレート関数と同名の関数テンプレートの場合、その他の条件が同じ場合、呼び出し時に非テンプレート関数が先に呼び出され、テンプレートからインスタンスは生成されません。より適切に一致する関数を生成できるテンプレートが選択されます。 (簡単に言うと、既製のものがある場合は既製のものを使用し、より適切なものがある場合はより適切なものを使用し、ない場合はテンプレートを使用します。)
3. テンプレート関数は自動型変換を許可しませんが、通常の関数は自動型変換を実行できます
2.5 関数テンプレートの宣言と定義の分離
分離を宣言して定義できる
違いは、テンプレート パラメータの宣言と定義を指定する必要があることです
//声明
template<typename T>
void Swap(T& left, T& right);
//定义
template<typename T>
void Swap(T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
3. クラステンプレート
3.1 クラステンプレートの定義形式
//可以声明多个模板参数
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
3.2 クラステンプレートのインスタンス化
クラス テンプレートのインスタンス化は、関数テンプレートのインスタンス化とは異なります。クラス テンプレートは明示的にインスタンス化されます。クラス テンプレートのインスタンス化では、クラス テンプレート名の後に <> を続ける必要があります。インスタンス化された型は、クラスである <> に配置できます。テンプレート名は実際のクラスではありませんが、インスタンス化の結果は実際のクラスです。
- 通常のクラスの場合、クラス名は型です。
- クラス テンプレートの場合、クラス名はタイプではありません。クラス名<type>< / a> はクラス全体の型です
3.3 クラステンプレートの宣言と定義の分離
// 类模板
// 注意:Stack不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Stack
{
private:
T* _a;
size_t _top;
size_t _capacity;
public:
// ...
Stack(size_t capacity = 10)
:_a(new T[capacity])
,_top(0)
,_capacity(capacity)
{
}
~Stack(); // 析构函数,在类中声明,类外定义
};
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template<class T>
Stack<T>::~Stack()
{
if (_a)
{
delete[] _a;
_a = nullptr;
}
_top = _capacity = 0;
}
int main()
{
// 类模板的使用都是显式实例化
// Stack是类名,Stack<int>才是类型
Stack<int*> st1;
Stack<int> st2;
return 0;
}
注: テンプレートでは、.h ヘッダー ファイルへの宣言の書き込みと、.cpp ソース ファイルへの定義の書き込みはサポートされていません。この方法で宣言と定義を別のファイルに分離すると、リンクエラーが発生しました。
4. まとめ
注: テンプレートがインスタンス化されていない場合、コンパイラは内部構文をチェックしません。
アドバンテージ:
- テンプレートはコードを再利用し、リソースを節約し、より迅速な反復開発を可能にするため、C++ 標準テンプレート ライブラリ (STL) が誕生しました。
- コードの柔軟性の向上
欠点:
- テンプレートによりコードが肥大化してコンパイル時間が長くなる可能性がある
- テンプレートのコンパイル エラーが発生すると、エラー メッセージが非常に煩雑になり、エラーを特定するのが困難になります。