記事のディレクトリ
ジェネリックプログラミング
最初に質問について考えてください:ユニバーサル交換機能を実装する方法は?
ここの多くの人々は関数のオーバーロードについて考えるかもしれません。はい、関数のオーバーロードはさまざまなタイプのデータの交換を実現できますが、大きな欠点もあります。
- オーバーロードされた関数はタイプが異なるだけで、コードの再利用率は比較的低く、新しいタイプが出現する限り、対応する関数を追加する必要があります。
- コードの保守性は比較的低く、エラーが発生するとすべてのオーバーロードが失敗する可能性があります
コンパイラーにモデルを与え、コンパイラーにそのモデルを使用させて、さまざまなタイプに従ってコードを生成させることはできますか?
ジェネリックプログラミングの概念はここに印刷されます。ジェネリックプログラミング:型とは関係のないジェネリックコードを書くことは、コードの再利用の手段です。テンプレートはジェネリックプログラミングの基盤です。
関数テンプレート
概念:
関数テンプレートは関数のファミリーを表します。関数テンプレートはタイプとは関係ありません。使用時にパラメーター化され、実際のパラメーターのタイプに従って関数の特定のタイプバージョンが生成されます。
関数テンプレート形式
template <typename T1、typename T2、…、typename Tn>
戻り値type関数名(パラメーターリスト){}
template<typename T>
void Swap( T& left, T& right) {
T temp = left;
left = right;
right = temp; }
//注意:typename是用来定义模板参数的关键字
//也可以使用class(切记:不能使用struct)
コンパイラーのコンパイル段階では、テンプレート関数を使用するために、コンパイラーは、渡された実際のパラメーターのタイプに基づいて、呼び出すための対応するタイプの関数を推定および生成する必要があります。
例:double型の関数テンプレートを使用する場合、コンパイラーは実際のパラメーターの型を推測してTをdouble型として判別し、double型を処理するコードを生成します。これは文字にも当てはまります。タイプ。
関数テンプレートのインスタンス化
- 暗黙的なインスタンス化:コンパイラーに、実際のパラメーターに基づいてテンプレートパラメーターの実際のタイプを推測させます
template<class T> T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.0, d2 = 20.0;
Add(a1, a2);
Add(d1, d2);
/*
该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,
编译器无法确定此处到底该将T确定为int 或者 double类型而报错
注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅
Add(a1, d1);
*/
// 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化
Add(a, (int)d);
return 0;
}
- 明示的なインスタンス化:関数名の後の<>でテンプレートパラメーターの実際のタイプを指定します
int main(void)
{
int a = 10;
double b = 20.0;
// 显式实例化
Add<int>(a, b);
return 0;
}
型が一致しない場合、コンパイラは暗黙的な型変換を実行しようとします。変換が失敗した場合、コンパイラはエラーを報告します。
関数テンプレートのパラメータマッチングの原則
- 非テンプレート関数は、同じ名前の関数テンプレートと同時に存在できます。また、関数テンプレートは、この非テンプレート関数としてインスタンス化することもできます。
- 非テンプレート関数と同じ名前の関数テンプレートの場合、他の条件が同じであれば、非テンプレート関数が最初に呼び出され、テンプレートからインスタンスは生成されません。テンプレートがより一致する関数を生成できる場合は、テンプレートが選択されます
- テンプレート関数は自動型変換を許可していませんが、通常の関数は自動型変換を実行できます
クラステンプレート
クラステンプレートの定義形式
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
例:
// 动态顺序表
// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Vector
{
public :
Vector(size_t capacity = 10)
: _pData(new T[capacity])
, _size(0)
, _capacity(capacity)
{
}
// 使用析构函数演示:在类中声明,在类外定义。
~Vector();
void PushBack(const T& data);
void PopBack();
// ...
size_t Size() {
return _size;}
T& operator[](size_t pos)
{
assert(pos < _size);
return _pData[pos];
}
private:
T* _pData;
size_t _size;
size_t _capacity;
};
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{
if(_pData)
delete[] _pData;
_size = _capacity = 0; }
クラステンプレートのインスタンス化
クラステンプレートのインスタンス化は、関数テンプレートのインスタンス化とは異なります。クラステンプレートのインスタンス化は、クラステンプレートの名前の後に<>を付けて、インスタンス化されたタイプを<>に入力する必要があります。クラステンプレートの名前は実際のクラスではなく、インスタンス化された結果は実際のクラスです。
// Vector类名,Vector<int>才是类型
Vector<int> s1;
Vector<double> s2;