C ++テンプレートの初見-ジェネリックプログラミング、関数テンプレート、クラステンプレート
1つ、ジェネリックプログラミング
1.1なぜジェネリックプログラミングを使うのですか?
一般的な交換関数を作成するために、関数のオーバーロードを使用できます。関数のオーバーロードの具体的な詳細については、次のブログを参照してください:
C ++ Elementary-名前空間、デフォルトのパラメーター、および関数のオーバーロード
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
void Swap(double& left, double& right)
{
double temp = left;
left = right;
right = temp;
}
void Swap(char& left, char& right)
{
char temp = left;
left = right;
right = temp;
}
関数のオーバーロードを使用すると、一般的な交換関数を実現できますが、2つの問題があります。
- 関数のオーバーロードは、タイプが異なるだけで、コードの再利用率が低く、新しいタイプが表示されたら、対応する関数を追加する必要があります。
- コードの保守性は低く、1つのエラーが原因ですべてのオーバーロードが失敗します。
したがって、人々はコンパイラにモデルを伝える方法を考え、コンパイラにモデルを使用させて、さまざまなタイプに従ってコードを生成させます。これにより、ジェネリックプログラミングが可能になります。
2.2ジェネリックプログラミングとは何ですか?
型とは関係のないジェネリックコードを書くことは、コードを再利用する手段です。テンプレートはジェネリックプログラミングの基盤です。
2、関数テンプレート
2.1関数テンプレートとは何ですか?
関数テンプレートは、関数のファミリを表します。関数テンプレートは、タイプとは何の関係もありません。これは、使用時にパラメータ化され、および機能の特定の種類のバージョンが実際のパラメータの種類に応じて生成されます。
2.2関数テンプレートの使い方は?
<1>関数テンプレート形式
template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}
これが栗です:
//2.2
template<typename T>
void Swap(T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
注意
typenameは、テンプレートパラメータキーワードを定義するために使用されます。また、classを使用することもできます(覚えておいてください:classの代わりにstructを使用することはできません)
2.3関数テンプレートの原理
関数テンプレートは青写真であり、それ自体は関数ではなく、特定のタイプの関数の特定の使用法を生成するための型のコンパイラです。したがって、実際には、テンプレートは、コンパイラーに実行する必要のある反復的な処理を引き渡すためのものです。
コンパイラーのコンパイル段階では、テンプレート関数を使用するために、コンパイラーは、に基づいて呼び出しに対応するタイプの関数を推定および生成する必要があります。引数の型が渡されました。。たとえば、double型の関数テンプレートを使用する場合、コンパイラは実際のパラメータの型を推測してTをdouble型として判別し、double型を処理するコードを生成します。これは文字にも当てはまります。タイプ。
<1>関数テンプレートのインスタンス化
関数テンプレートがさまざまなタイプのパラメーターで使用される場合、それは関数テンプレートのインスタンス化と呼ばれます。テンプレートパラメータのインスタンス化は、暗黙的なインスタンス化と明示的なインスタンス化に分けられます。
- 暗黙的なインスタンス化:コンパイラーに、実際のパラメーターに基づいてテンプレートパラメーターの実際のタイプを推測させます
- 明示的なインスタンス化:関数名の後に<>を付けて、テンプレートパラメータの実際の型を指定します。
型が一致しない場合、コンパイラは暗黙的な型変換を実行しようとします。変換が失敗した場合、コンパイラはエラーを報告します。
<2>テンプレートパラメータのマッチング原則
- 非テンプレート関数は、同じ名前の関数テンプレートと同時に存在でき、関数テンプレートは非テンプレート関数としてインスタンス化することもできます。
// 专门处理int的加法函数
int Add(int left, int right)
{
return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
return left + right;
}
void Test()
{
Add(1, 2); // 与非模板函数匹配,编译器不需要特化
Add<int>(1, 2); // 调用编译器特化的Add版本
}
int main()
{
Test();
return 0;
}
2.非テンプレート関数と同じ名前の関数テンプレートの場合、他の条件が同じであると、転送中に非テンプレート関数が最初に呼び出され、テンプレートからインスタンスが生成されません。テンプレートがより一致する関数を生成できる場合は、テンプレートが選択されます。
// 专门处理int的加法函数
int Add(int left, int right)
{
return left + right;
}
// 通用加法函数
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
return left + right;
}
void Test()
{
Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化
Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
}
3.テンプレート関数は自動型変換を許可していませんが、通常の関数は自動型変換を実行できます
3、クラステンプレート
3.1クラステンプレートの定義形式
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()
{
if(_pData)
delete[] _pData;
_size = _capacity = 0;
}
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;
};
ここで、クラス内の関数をクラス外で定義するように宣言する場合は、デストラクタなどのテンプレートパラメータリストを追加する必要があることに注意してください。
3.2クラステンプレートのインスタンス化
上記のクラステンプレートの使い方は?
クラステンプレートのインスタンス化は、関数テンプレートのインスタンス化とは異なります。クラステンプレートのインスタンス化は、クラステンプレート名の後に<>が続く、その後インスタンス化されたタイプを<>に入れますつまり、クラステンプレート名は実際のクラスではありませんが、インスタンス化の結果は実際のクラスです。
int main()
{
Vector<int> s1;
Vector<double> s2;
Vector<char> s3;
return 0;
}