模板编程
函数模板使用
直接上代码;
template<typename T>//只对下一个生效,在后面需要重新再定义模板,这里的T为泛型类型
T add(T a, T b)
{
return a + b;
}
int main()
{
double a = 0.555, b = 0.9;
int ia = 4, ib = 6;
std::cout << add(a, b)<<std::endl;
std::cout<<add(ia , ib);
return 0;
}
结果
1.455
10
函数模板格式:
template <模板参数表>
函数定义(形参表可以包含模板参数表里的参数)
template <typename T,typename U >//注意使用逗号隔开,每个参数前面都要加typename
template <typename T,class U >//class与template,用处相同
在函数模板这里,class不是指类,其作用与typename相同。
函数模板使用注意:
函数模板使用时,传递参数时,可以进行类型自动推导,但参数类型不自动转换,因此对于参数类型要求严格,比如下面这个例子就会报错。因为在模板中T类型由a、b类型确认,但所给a、b类型都不同导致T的类型不确定,直接报错
template<typename T>
T add(T a, T b)
{
return a + b;
}
double add(double a,double b)
{
return a+b+2;
}
///
double a = 0.555,c=0.1;int b = 9;
add(a,b)//此时会调用第二个add,因为普通函数会自动类型转换,而模板函数匹配不上。
add<>(a,c);//要用模板函数调用
add(s,c);//默认情况下,会先看普通函数,没有符合的。再看模板函数
函数模板的编译过程:
再编译器遇到函数模板时,并不会生成代码(不会编译),只检查语法错误;只有再实例化模板的一个特点版本时,编译器才会生成代码。
类模板使用
类模板的实例化:不同于函数模板使用时,类型会自动推导,类模板必须显式指定类型。见代码
template <class nn>
class farther
{
public:
float sum;
farther(nn a, nn b)
{
sum = a+ b;
}
void sdf(nn x);
int get_sum();
template<class tr>
tr mlu(tr a);
};
template<class nn>//不能少!!
int farther<nn>::get_sum()//对于在外部定义的类模板成员函数,仍然需要加 template <class nn>,其它与普通成员函数定义相同
{
return sum;
}
template <class nn>//不能少!!
void farther<nn>::sdf(nn x)//含有与类模板一样模板参数的成员函数
{
++sum;
}
template<class nn>//即使是成员模板,所属的类模板的模板参数也不能少!!
template<class tr>//类模板自己的模板参数
tr farther<nn>::mlu(tr a)
{
return a * a;
}
##############################################################
int x1 = 55, x2 = 15;
farther<int>fa(x1,x2);//必须显示指定类型
cout << fa.sum;//结果为70
string as = "sdf";
fa.sdf(as);//此处代码编译前不会报错,但编译后,就会报错,因为此时的泛型数据nn已经确定为整型
//而成员函数的数据类型与类模板是一样的
float mm = 5.5;
fa.sdf(mm);
cout << float(fa.sum);//此时输出为75,因为类型已经确定是int(此时的模板函数已经编译了,就和一般函数一样),所以虽然传递参数是float,但最后会类型转换为int;
类模板的成员函数:
由于类模板在实例化后,每个实例都有自己的类型版本,因此类模板的成员函数(j即使是普通函数)也会具有和类模板一样的模板参数,定义使用见上面代码。(最好把代码理解,看注释,已经能理解到,类模板与类成员函数的模板参数是一致的)。
成员模板(copy的C++ primer):一个类(无论是普通类,还是类模板)可以包含本身就是模板的成员函数,这就是成员模板(成员模板不能是虚函数)
普通类的成员模板
直接看代码,很简单
//普通类
class farther
{
template<class tr>
tr mlu(tr a);//成员模板声明
}
//成员模板
tr farther<nn>::mlu(tr a)
{
return a * a;
}
类模板的成员模板
从上面代码,摘录部分:(具体见代码)
//类模板
template <class nn>
class farther
{
public:
float sum;
farther(nn a, nn b)
{
sum = a+ b;
}
void sdf(nn x);
int get_sum();
template<class tr>
tr mlu(tr a);
};
//成员模板
template<class nn>//即使是成员模板,所属的类模板的模板参数也不能少!!
template<class tr>//类模板自己的模板参数
tr farther<nn>::mlu(tr a)
{
return a * a;
}
类模板派生类
class child : public farther<int>
//这里int是对所继承类的模板参数类型确定
{
public:
child(int x1,int x2):farther(x1,x2)
{
sum = x1 * x2; ;
};
};
template <class XX>
class child2 : public farther<XX>
//此时派生类也是类模板,其模板参数设置与基类相同
{
public:
child(XX x1, XX x2) :farther(x1, x2)
{
sum = x1 * x2; ;
};
};
* x2; ;
};
};
template <class XX>
class child2 : public farther<XX>
//此时派生类也是类模板,其模板参数设置与基类相同
{
public:
child(XX x1, XX x2) :farther(x1, x2)
{
sum = x1 * x2; ;
};
};