関数テンプレート
C++ を始めると、多くの人が swap(int&, int&) のような関数の同様のコードは次のとおりです:
void swap(int&a , int& b) { int temp = a; a = b; b = temp; }
ただし、long、string、およびカスタム クラス スワップ関数をサポートする場合、コードは上記のコードに似ていますが、現時点では型が異なります。 、スワップの関数テンプレートを定義します。それだけです。 さまざまな種類のスワップ関数コードを再利用するには、関数テンプレートの宣言形式は次のとおりです。
template <class identifier> function_declaration; template <typename identifier> function_declaration;
スワップ関数テンプレートの宣言と定義コードは次のとおりです。
//method.h template<typename T> void swap(T& t1, T& t2); #include "method.cpp"
//method.cpp template<typename T> void swap(T& t1, T& t2) { T tmpT; tmpT = t1; t1 = t2; t2 = tmpT; }
上記はテンプレートの宣言と定義です。 テンプレートのインスタンス化はコンパイラによって行われるものであり、プログラマとは関係ありません。では、上記のテンプレートを使用する方法は次のとおりです。
ここでは swap 関数が使用されており、swap の定義を含める必要があります。そうでないとコンパイルがエラーになります。これは一般的な関数の使用方法と異なります。したがって、method.h ファイルの最後の行に #include を追加する必要があります。 「メソッド.cpp」。 クラス テンプレート単純なスタック クラスを作成するとします。このスタックは、int 型、long 型、string 型などをサポートできます。クラス テンプレートを使用しない場合、コードは基本的に 3 つ以上のスタック クラスを作成する必要があります。同様に、クラス テンプレートを使用して、単純なスタック テンプレートを定義し、必要に応じてそれを int スタック、long スタック、または string スタックとしてインスタンス化できます。//main.cpp #include <stdio.h> #include "method.h" int main() { //模板方法 int num1 = 1, num2 = 2; swap<int>(num1, num2); printf("num1:%d, num2:%d\n", num1, num2); return 0; }
//statck.h template <class T> class Stack { public: Stack(); ~Stack(); void push(T t); T pop(); bool isEmpty(); private: T *m_pT; int m_maxSize; int m_size; }; #include "stack.cpp"
//stack.cpp template <class T> Stack<T>::Stack(){ m_maxSize = 100; m_size = 0; m_pT = new T[m_maxSize]; } template <class T> Stack<T>::~Stack() { delete [] m_pT ; } template <class T> void Stack<T>::push(T t) { m_size++; m_pT[m_size - 1] = t; } template <class T> T Stack<T>::pop() { T t = m_pT[m_size - 1]; m_size--; return t; } template <class T> bool Stack<T>::isEmpty() { return m_size == 0; }
テンプレート パラメーター
テンプレートには Type パラメーターを含めることができます。また、通常の型パラメーター int または//main.cpp #include <stdio.h> #include "stack.h" int main() { Stack<int> intStack; intStack.push(1); intStack.push(2); intStack.push(3); while (!intStack.isEmpty()) { printf("num:%d\n", intStack.pop()); } return 0; }
template<class T, T def_val> class Stack{...}
//statck.h template <class T,int maxsize = 100> class Stack { public: Stack(); ~Stack(); void push(T t); T pop(); bool isEmpty(); private: T *m_pT; int m_maxSize; int m_size; }; #include "stack.cpp"
使用例は次のとおりです。
テンプレートのさまざまな実装を定義したい場合は、テンプレートの特殊化を使用できます。たとえば、定義したスタック クラス テンプレートが char* 型スタックの場合、char ポインタのみが保存され、char ポインタが指すメモリは保存されるため、char のすべてのデータをスタック クラスにコピーしたいと考えます。が無効になる可能性があり、スタックによってポップアップされたスタック要素が無効になる可能性があります。 char ポインタが指すメモリが無効になる可能性があります。また、私たちが定義したスワップ関数テンプレートもありますが、ベクトルやリストなどのコンテナ型を使用する場合、コンテナによって保存されるオブジェクトが大きい場合、一時的に大きなオブジェクトを生成する必要があるため、大量のメモリを占有してパフォーマンスが低下します。を保存するには、特殊化が必要です。これを解決できます。
関数テンプレートの特殊化
多くの要素を含む 2 つのベクトルがある状況を swap 関数で処理したいとします。元の swap 関数を使用して、 tmpT = を実行します。 t1 は t1 のすべての要素をコピーする必要があるため、大量のメモリが消費され、パフォーマンスが低下します。そのため、この問題は、vector.swap 関数によって解決されます。コードは次のとおりです。これは特殊化であり、それを記述するときにテンプレートが使用されないことを示します。 パラメーターと使用例は次のとおりです。
//stack.cpp template <class T,int maxsize> Stack<T, maxsize>::Stack(){ m_maxSize = maxsize; m_size = 0; m_pT = new T[m_maxSize]; } template <class T,int maxsize> Stack<T, maxsize>::~Stack() { delete [] m_pT ; } template <class T,int maxsize> void Stack<T, maxsize>::push(T t) { m_size++; m_pT[m_size - 1] = t; } template <class T,int maxsize> T Stack<T, maxsize>::pop() { T t = m_pT[m_size - 1]; m_size--; return t; } template <class T,int maxsize> bool Stack<T, maxsize>::isEmpty() { return m_size == 0; }
vector
//main.cpp #include <stdio.h> #include "stack.h" int main() { int maxsize = 1024; Stack<int,1024> intStack; for (int i = 0; i < maxsize; i++) { intStack.push(i); } while (!intStack.isEmpty()) { printf("num:%d\n", intStack.pop()); } return 0; }
を
//method.h template<class T> void swap(T& t1, T& t2); #include "method.cpp"
以下の比較コードを見てください:
#include <vector> using namespace std; template<class T> void swap(T& t1, T& t2) { T tmpT; tmpT = t1; t1 = t2; t2 = tmpT; } template<> void swap(std::vector<int>& t1, std::vector<int>& t2) { t1.swap(t2); }
//main.cpp #include <stdio.h> #include <vector> #include <string> #include "method.h" int main() { using namespace std; //模板方法 string str1 = "1", str2 = "2"; swap(str1, str2); printf("str1:%s, str2:%s\n", str1.c_str(), str2.c_str()); vector<int> v1, v2; v1.push_back(1); v2.push_back(2); swap(v1, v2); for (int i = 0; i < v1.size(); i++) { printf("v1[%d]:%d\n", i, v1[i]); } for (int i = 0; i < v2.size(); i++) { printf("v2[%d]:%d\n", i, v2[i]); } return 0; }
2つの整数を比較する場合、比較のequalメソッドは正しいですが、比較のテンプレートパラメータがchar*の場合、テンプレートは機能しないため、修正しました次のようになります:
template<> void swap(std::vector<int>& t1, std::vector<int>& t2) { t1.swap(t2); }
main.cpp ファイルは変更されず、このコードは正常に動作します。
テンプレート型変換
カスタマイズされたスタック テンプレートをまだ覚えていますか? 私たちのプログラムでは、Shape クラスと Circle クラスを定義すると仮定した場合、コードは次のとおりです:
template<class V> void swap(std::vector<V>& t1, std::vector<V>& t2) { t1.swap(t2); }
//compare.h template <class T> class compare { public: bool equal(T t1, T t2) { return t1 == t2; } };
#include <iostream> #include "compare.h" int main() { using namespace std; char str1[] = "Hello"; char str2[] = "Hello"; compare<int> c1; compare<char *> c2; cout << c1.equal(1, 1) << endl; //比较两个int类型的参数 cout << c2.equal(str1, str2) << endl; //比较两个char *类型的参数 return 0; }
//compare.h #include <string.h> template <class T> class compare { public: bool equal(T t1, T t2) { return t1 == t2; } }; template<>class compare<char *> { public: bool equal(char* t1, char* t2) { return strcmp(t1, t2) == 0; } };
//shape.h class Shape { }; class Circle : public Shape { };
その他
クラスにはテンプレート パラメーターがありませんが、メンバー関数にはテンプレート パラメーターがあることが可能です。コードは次のとおりです。
//main.cpp #include <stdio.h> #include "stack.h" #include "shape.h" int main() { Stack<Circle*> pcircleStack; Stack<Shape*> pshapeStack; pcircleStack.push(new Circle); pshapeStack = pcircleStack; return 0; }
Util を静的として宣言することもできます。コードは次のとおりです。