非类型(普通)参数模板

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);


 

几点注意

如果在全局域中声明了与模板参数同名的对象函数或类型,则该全局名将被隐藏。

在下面的例子中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 );


 ​