天天看點

【C++模闆】C++的函數模闆和類模闆|普通參數模闆、類參數模闆

非類型(普通)參數模闆

template <class T, int size,int size2 >
void f(char a) 
{

char temp[size];
char temp[size2];
    ......
}

void main()
{

f<10,10>(1);
}
      

類型參數模闆

簡介:

//類聲明
template<class T1, class T2> 
class VarToVar 
{
private :
T1 m_source_vars_list;
T2 m_dest_vars_list;
public:
int Add(T1 source_node, T2 dest_node);
VarToVar();
virtual ~VarToVar();

};      

詳細:

了解這個 typedef double Type; 有助于了解模闆, Type就代表了double, Type data  相當于 

double data。

1、函數模闆

函數模闆的用途:

類屬函數指一個函數對不同類型的資料完成相同的操作。

1、宏實作

#define max(a,b) ((a)>(b)?(a):(b))      

不足之處:隻能實作簡單的功能,并且存在不作類型檢查以及重複計算等問題。

2、函數重載

int max(int,int);
double max(double,double);
A max(A,A);
      

不足之處:需要定義的重載函數太多,如果定義不全會有問題。

如:

cout << max(‘3’,’5’); 将輸出53而非‘5’。

3、指針實作

例:編寫一個排序(sort)函數,使其能對各種資料進行排序(整型數序列、浮點數序列以及某個類的對象序列等)。

void sort(void *base, //需排序的資料首位址
unsigned int count, //資料元素的個數
unsigned int element_size, //資料元素的大小
int (*cmp)(void *, void *) //比較兩個資料元素
//大小的函數指針
         )
{
//取第i個元素
    (char *)base + i *element_size
//比較第i個和第j個元素的大小
    (*cmp)((char *)base + i * element_size,
           (char *)base + j * element_size
          )
//交換第i個和第j個元素
char *p1 = (char *)base + i * element_size,
*p2 = (char *)base + j * element_size;
for (k = 0; k < element_size; k++)
    {
char temp = p1[k];
p1[k] = p2[k];
p2[k] = temp;
    }
}

int int_compare(void *p1, void *p2)
{
if (*(int *)p1 < * (int *)p2)
return –1;
else if (*(int *)p1 > *(int *)p2)
return 1;
else
return 0;
}

int double_compare(void *p1, void *p2)
{
if (*(double *)p1 < * (double *)p2)
return –1;
182
else if (*(double *)p1 > *(double *)p2)
return 1;
else
return 0;
}

int A_compare(void *p1, void *p2)
{
if (*(A *)p1 < * (A *)p2) //類A需重載操作符:<
return –1;
else if (*(A *)p1 > *(A *)p2) //類A需重載操作符:>
return 1;
else
return 0;
}

…
int a[100];
sort(a, 100, sizeof(int), int_compare);
double b[200];
sort(b, 200, sizeof(double), double_compare);
A c[300];
sort(c, 300, sizeof(A), A_compare);
      

不足之處:需要定義額外的參數,并且有大量的指針運算,使得實作起來麻煩、可讀性差。

例:上述的排序用函數模闆來實作。

template <class Type>

Type min( Type a, Type b ) ?

{

return a < b ? a : b;

}      

 Type統包了:int、float、double、string、char 等等類型,具體是哪一類,看實際引用,這就不必為每一個類型的資料都寫一個函數了。

template <class T> //定義一個通用的參數T ,這個T指代哪種類型,視執行個體化為哪種類型

void sort(T elements[], unsigned int count)
{
//取第i個元素
elements [i]
//比較第i個和第j個元素的大小
elements [i] < elements [j]
//交換第i個和第j個元素
T temp = elements [i];
elements [i] = elements [j];
elements [j] = temp;
}
......
int a[100];
sort(a, 100);
double b[200];
sort(b, 200);
A c[300]; //類A中需重載操作符:<和=,給出拷貝構造函數
sort(c, 300);      

函數模闆定義了一類重載的函數,使用函數模闆所定義的函數(模闆函數)時,編譯系統會自動把函數模闆執行個體化。

模闆的參數可以有多個,用逗号分隔它們,如:

template <class T1, class T2>  //T1\T2 代表::int、float、double、string、char 等等類型
void f(T1 a, T2 b)
{ ......
}
      

模闆也可以帶普通參數(非類型參數<非代表類型的參數>因為已經具體指明了參數類型)),它們須放在類型參數的後面,

調用時需顯式執行個體化

,如:

template <class T, int size>
void f(T a) 
{

T temp[size];
    ......
}

void main()
{

f<int, 10>(1);
}
      

有時,需要把函數模闆與函數重載結合起來用,例如:

template <class T>
T max(T a, T b)
{
return a > b ? a : b;
}
…
int x, y, z;
double l, m, n;
z = max(x, y);
l = max(m, n);      

問題:max(x,m)如何處理?

定義一個max的重載函數:

double max(int a, double b)
{
return a > b ? a : b;
}

      

VC template模闆的使用   類模闆

//類聲明
template<class T1, class T2> 
class VarToVar 
{
private :
T1 m_source_vars_list;
T2 m_dest_vars_list;
public:
int Add(T1 source_node, T2 dest_node);
VarToVar();
virtual ~VarToVar();

};

//函數實作體

template<class T1, class T2>
VarToVar<T1, T2>::VarToVar()
{

}

template<class T1, class T2>
VarToVar<T1, T2>::~VarToVar()
{

}

template<class T1, class T2>
int VarToVar<T1, T2>::Add(T1 source_node, T2 dest_node)
{
return FALSE;
}

//調用

VarToVar<int, int > a;    //用int 模闆的類 示例化 a 

a.Add(3,4);
      

​​http://zhanyonhu.blog.163.com/blog/static/1618604420083167842277/​​

幾點注意

①  如果在全局域中聲明了與模闆參數同名的對象函數或類型,則該全局名将被隐藏。

在下面的例子中tmp 的類型不是double 是模闆參數Type

typedef double Type;
template <class Type>

Type min( Type a, Type b )
{
//tmp類型為模闆參數?Type
//不是全局?typedef

Type tmp = a < b ? a : b;

return tmp;
}
      

②  在函數模闆定義中聲明的對象或類型不能與模闆參數同名

template <class Type>

Type min( Type a, Type b )
{

//錯誤:重新聲明模闆參數?Type
typedef double Type;
Type tmp = a < b ? a : b;
return tmp;
}

      

③  模闆類型參數名可以被用來指定函數模闆的傳回位

// ok: T1 表示 min() 的傳回類型
// T2 和 T3 表示參數類型

template <class T1, class T2, class T3>

T1 min( T2, T3 );

      

④  模闆參數名在同一模闆參數表中隻能被使用一次,但是模闆參數名可以在多個函數模闆聲明或定義之間被重複使用

// 錯誤: 模闆參數名 Type 的非法重複使用

template <class Type, class Type>

Type min( Type, Type );



// ok: 名字 Type 在不同模闆之間重複使用

template <class Type>

Type min( Type, Type );

template <class Type>

Type max( Type, Type );

      

⑤  如果一個函數模闆有一個以上的模闆類型參數則每個模闆類型參數前面都必須有關鍵字class 或typename

// ok:關鍵字typename和class可以混用
template <typename T, class U>

T minus( T *, U );

//錯誤:必須是?<typename T, class U>或<typename T, typename U>
template <typename T, U>

T sum( T *, U );      

⑥ 為了分析模闆定義編譯器必須能夠區分出是類型以及不是類型的表達式對于編譯器來說它并不總是能夠區分出模闆定義中的哪些表達式是類型例如如果編譯器在模闆定義中遇到表達式Parm::name 且Parm 這個模闆類型參數代表了一個類那麼name 引用的是Parm 的一個類型成員嗎.

template <class Parm, class U>
Parm minus( Parm *array, U value )
{

Parm::name *p;
// 這是一個指針聲明還是乘法乘法
}      

編譯器不知道name 是否為一個類型因為它隻有在模闆被執行個體化之後才能找到Parm 表示的類的定義為了讓編譯器能夠分析模闆定義使用者必須訓示編譯器哪些表達式是類型表達式告訴編譯器一個表達式是類型表達式的機制是在表達式前加上關鍵字typename 例如如果我們想讓函數模闆minus()的表達式Parm::name 是個類型名因而使整個表達式是一個指針聲明我們應如下修改

關鍵字typename 也可以被用在模闆參數表中以訓示一個模闆參數是一個類型

template <class Parm, class U>

Parm minus( Parm* array, U value )

{

typename Parm::name * p; // ok: 指針聲明

}      

⑦ 如同非模闆函數一樣函數模闆也可以被聲明為inline 或extern 應該把訓示符放在模闆參數表後面而不是在關鍵字template 前面

// ok: 關鍵字跟在模闆參數表之後

template <typename Type>

inline

Type min( Type, Type );

      

繼續閱讀