C++のテンプレートと汎用プログラミング(一、テンプレート定義)
引用する
テンプレートに接触する前に、比較的サイズの関数を作成する場合は、次のように書きます.
int compare(const string &v1, const string &v2) { if (v1 < v2) return -1; if (v2 < v1) return 1; return 0; }
int compare(const double &v1, const double &v2) { if (v1 < v2) return -1; if (v2 < v1) return 1; return 0; }
これらの関数はほぼ同じで、それらの間の唯一の違いはパラメータのタイプであり、各関数の関数体は同じである.
この方法の欠点は,各関数が1つのデータ型にのみ適用され,新しいデータ型に遭遇すると,新しい関数を追加する必要があることである.
すべてのデータ型に適用できるテクノロジーはありますか?技術の革新は人間の怠惰に源を発し、ちょうどC++は私たちにこのような技術--関数テンプレートを提供してくれた.
関数テンプレートの動作原理
関数テンプレートはタイプとは独立した関数で、コンパイラはコンパイル中にプログラマが提供した実際のパラメータタイプに基づいてパラメータを置き換え、置き換えたコードを実際のパラメータで直接記述したコードのようにします.
関数テンプレートの定義
テンプレート定義はキーワードtemplateで始まり、テンプレートパラメータテーブルに続き、テンプレートパラメータテーブルはカッコで囲まれた1つ以上のテンプレートパラメータのリストであり、パラメータ間はカンマで区切られ、後で私たちが普段書いた関数宣言に続き、唯一の違いはパラメータタイプが実際の意味のないタイプにすぎないことです.テンプレートパラメータテーブルを空にすることはできません.
//implement strcmp-like generic compare function //returns 0 if the values are equal, 1 if v1 is larger, -1 if v1 is smaller template int compare(const T &v1, const T &v2) { if (v1 < v2) return -1; if (v2 < v1) return 1; return 0; }
関数テンプレートの使用
int main () { //T is int; //compiler instantiates int compare(const int&, const int&) cout << compare(1, 0) << endl; //T is string; //compiler instantiates int compare(const string&, const string&) string s1 = "hi", s2 = "world"; cout << compare(s1, s2) << endl; return 0; }
inline関数テンプレート
//ok: inline specifier follows template parameter list template inline T min(const T&, const T&); //error: incorrect placement of inline specifier inline template T min(const T&, const T&);
クラステンプレートの定義
template
class Queue { public: Queue (); //default constructor Type &front (); //return element from head of Queue const Type &front () const; void push (const Type &);//add element to back of Queue void pop(); //remove element from head of Queue bool empty() const; //true if no elements in the Queue private: //... };
クラステンプレートの使用
Queue qi; //Queue that holds ints Queue< vector> qc; //Queue that holds vectors of doubles Queue qs; //Queue that holds strings
テンプレートパラメータ
1、テンプレートパラメータは、タイプを表すタイプパラメータであってもよく、定数式を表す非タイプパラメータであってもよい.タイプパラメータの場合、このパラメータは未知のタイプを表し、非タイプパラメータの場合、未知の値であることがわかります.
2、関数パラメータのように、プログラマがテンプレートパラメータのために選択した名前には本質的な意味がありません.
3、テンプレートパラメータが表すタイプまたは値を使用する場合は、対応するテンプレートパラメータと同じ名前を使用できます.
4、テンプレートパラメータの名前は、テンプレートパラメータとして宣言した後、テンプレート宣言または定義の末尾まで使用できます.
5、テンプレートパラメータは通常の名前マスク規則に従う.グローバル役割ドメインで宣言されたオブジェクト、関数、またはタイプと同じ名前のテンプレートパラメータは、グローバル名をマスクします.
typedef double T; template T calc(const T &a, const T &b) { //tmp has the type of the template parameter T //not that of the global typedef T tmp = a; //... return tmp;}6、テンプレート形参として使用する名前はテンプレート内部で再利用できない
template T calc(const T &a, const T &b) { typedef double T;//error: redeclares template parameter T T tmp = a; //... return tmp;}7、関数パラメータの名前を再利用できるように、テンプレートパラメータの名前も異なるテンプレートで再利用できます.
テンプレートに接触する前に、比較的サイズの関数を作成する場合は、次のように書きます.
int compare(const string &v1, const string &v2) { if (v1 < v2) return -1; if (v2 < v1) return 1; return 0; }
int compare(const double &v1, const double &v2) { if (v1 < v2) return -1; if (v2 < v1) return 1; return 0; }
これらの関数はほぼ同じで、それらの間の唯一の違いはパラメータのタイプであり、各関数の関数体は同じである.
この方法の欠点は,各関数が1つのデータ型にのみ適用され,新しいデータ型に遭遇すると,新しい関数を追加する必要があることである.
すべてのデータ型に適用できるテクノロジーはありますか?技術の革新は人間の怠惰に源を発し、ちょうどC++は私たちにこのような技術--関数テンプレートを提供してくれた.
関数テンプレートの動作原理
関数テンプレートはタイプとは独立した関数で、コンパイラはコンパイル中にプログラマが提供した実際のパラメータタイプに基づいてパラメータを置き換え、置き換えたコードを実際のパラメータで直接記述したコードのようにします.
関数テンプレートの定義
テンプレート定義はキーワードtemplateで始まり、テンプレートパラメータテーブルに続き、テンプレートパラメータテーブルはカッコで囲まれた1つ以上のテンプレートパラメータのリストであり、パラメータ間はカンマで区切られ、後で私たちが普段書いた関数宣言に続き、唯一の違いはパラメータタイプが実際の意味のないタイプにすぎないことです.テンプレートパラメータテーブルを空にすることはできません.
//implement strcmp-like generic compare function //returns 0 if the values are equal, 1 if v1 is larger, -1 if v1 is smaller template
関数テンプレートの使用
int main () { //T is int; //compiler instantiates int compare(const int&, const int&) cout << compare(1, 0) << endl; //T is string; //compiler instantiates int compare(const string&, const string&) string s1 = "hi", s2 = "world"; cout << compare(s1, s2) << endl; return 0; }
inline関数テンプレート
//ok: inline specifier follows template parameter list template
クラステンプレートの定義
template
class Queue { public: Queue (); //default constructor Type &front (); //return element from head of Queue const Type &front () const; void push (const Type &);//add element to back of Queue void pop(); //remove element from head of Queue bool empty() const; //true if no elements in the Queue private: //... };
クラステンプレートの使用
Queue
テンプレートパラメータ
1、テンプレートパラメータは、タイプを表すタイプパラメータであってもよく、定数式を表す非タイプパラメータであってもよい.タイプパラメータの場合、このパラメータは未知のタイプを表し、非タイプパラメータの場合、未知の値であることがわかります.
2、関数パラメータのように、プログラマがテンプレートパラメータのために選択した名前には本質的な意味がありません.
3、テンプレートパラメータが表すタイプまたは値を使用する場合は、対応するテンプレートパラメータと同じ名前を使用できます.
4、テンプレートパラメータの名前は、テンプレートパラメータとして宣言した後、テンプレート宣言または定義の末尾まで使用できます.
5、テンプレートパラメータは通常の名前マスク規則に従う.グローバル役割ドメインで宣言されたオブジェクト、関数、またはタイプと同じ名前のテンプレートパラメータは、グローバル名をマスクします.
typedef double T; template
template
// ok: reuses parameter type name across different templates
template <class T> T calc (const T&, const T&) ;
template <class T> int compare(const T&, const T&) ;
8、 , 。
// declares compare but does not define it
template <class T> int compare(const T&, const T&) ;
9、 class typename,
,
// error: must precede U by either typename or class
template <typename T, U> T calc (const T&, const U&) ;
size_type , :
template <class Parm, class U>
Parm fcn(Parm* array, U value)
{
typename Parm::size_type * p; // ok: declares p to be a pointer
}
, 。 ,
array_init 。 ,
// initialize elements of an array to zero
template <class T, size_t N> void array_init(T (&parm)[N])
{
for (size_t i = 0; i != N; ++i) {
parm[i] = 0;
}
}
1、 ,
2、