函数模板–泛化类型–参数个数固定
//模板的定义只能写在全局,命令空间和类中,不能写在函数中
template <typename T>
T add(T a_t, T b_t)
{
cout << "a+b = " << a_t + b_t << endl;
return a_t + b_t;
}
int main(void)
{
//实例化是指将函数中的T替换为具体的类型,然后生成对应的函数代码
//在这个基础上,其实模板编程对编译器来说并没有减少代码,但对开发者来说,少写了很多代码
//比如这里,如果进行各种类型的两个数加减,不用定义多个重载函数
add(5, 2);//1.先将函数模板,实例化成模板函数 2.再调用实例化的函数
add(5.1, 2.1);//隐式实例化
add<int>(5.1, 2.1);//显示实例化模板函数
return 0;
自定义类型的函数模板–泛化参数个数–类型固定
multy.h
class Frame{
public:
int W = 1920;
int H = 1080;
static int get_h()
{
return 1080;
}
static int get_w()
{
return 1920;
}
};
//这里跟上面的函数模板有一点不同,它在内部调用了自定义类的成员函数,因此类型其实是固定的。上面是泛化参数的类型,但这里是通过加入不固定参数,来泛化固定类型参数的个数。
template<typename T, typename... Ts>//参数头是不固定数量参数
void myfunc()//参数头是不固定数量参数,它的形参中不推荐含有模板头中定义的类型,因为模板实例化时,并不知道会传进来几个类型,还有下面递归调用时,参数的数量是不确定的
{
//可以发现还不知道要实例化成什么类型就已经调用这个类型的成员函数了,这说明此种泛化编程传进来的都是特定类型,那为什么还要泛化呢,因为即使类型是确定的,但类型的个数不固定也是一种泛化编程,而且c++的不固定参数数量函数只能用泛化编程来实现。
cout << "T::get_h():" << T::get_h() << " size:" << sizeof...(Ts) << endl;
T t;
cout << "t.W:" << t.W << " size:" << sizeof...(Ts) << endl;//c++17才支持sizeof...(Ts)
if constexpr (sizeof...(Ts) > 0) //constexpr是必要的,不然无法编译,因为当参数包里的数据为0个时,并没有对应的函数可以调用,实测虽然设置了>0的条件依然无法编译。这里参考了webrtc-m120源码
{
myfunc<Ts...>();//并没有方法可以取到参数包的数据,所以需要用的到特殊机制,这里使用递归调用 //这里必须显示调用
}
}
main.cpp
int main(void)
{
//这里必须显示调用
myfunc<Frame, Frame, Frame, Frame>();//先实例化类型和类型的个数,然后再调用实例化好的函数。//实例化个数其实就是实例化参数包,比如 myfunc<Ts...>();,可以堪称填进取具体数量的参数,如myfunc<Frame, Frame, Frame>();
return 0;
}
类模板
1.成员函数在类中
Test.h
template<typename T1, typename T2>
class Test
{
public:
Test(T1 a_t, T2 b_t)
{
a = a_t;
b = b_t;
}
T1 a;
T2 b;
void show(T1 a_tt, T2 b_tt)
{
cout << "a_tt:" << a_tt << " b_tt:" << b_tt << endl;
cout << "a:" << a << " b:" << b << endl;
}
};
main.cpp
int main(void)
{
//类的实例化过程必须显示,不能隐式
Test<int, double> test(1, 1.1);//1.先将类模板,实例化成模板类 2.再用实例化好的类定义对象
test.show(2, 2.2);//带有模板形参的成员函数,只有被调用或取地址时才会被实例化,它的实例化跟调用它的对象一致
return 0;
2.成员函数写在类外
test.h
template<typename T1, typename T2>
class Test
{
public:
Test(T1 a_t, T2 b_t);
T1 a;
T2 b;
void show(T1 a_tt, T2 b_tt);
};
//注意模板成员函数的实现不能写在.cpp文件中,因为这些还未实例化,不能编译
template <typename T1, typename T2>//模板头
void Test<T1, T2>::show(T1 a_tt, T2 b_tt) //类名后需要带上模板参数表
{
cout << "a_tt:" << a_tt << " b_tt:" << b_tt << endl;
cout << "a:" << a << " b:" << b << endl;
}
template <typename T1, typename T2>//每个成员函数前都要写,它仅对紧接着的函数其作用
Test<T1, T2>::Test(T1 a_t, T2 b_t)
{
a = a_t;
b = b_t;
}
main.cpp
int main(void)
{
//类的实例化过程必须显示,不能隐式
Test<int, double> test(1, 1.1);//1.先将类模板,实例化成模板类 2.再用实例化好的类定义对象
test.show(2, 2.2);//带有模板形参的成员函数,只有被调用或取地址时才会被实例化,它的实例化类型跟调用它的对象一致
return 0;