C++ 模板泛型编程
1、函数模板
概述,泛型编程,不局限于特点类型的方式编写代码,使用泛型编程需要指定实际操作的类型
// typename 可以写成class,多个参数用,分割
template<typename T>
T fun(T a,T b)
{
return a+b;
}
int a = fun(1,3); // 通过实参推断出来
// 非类型模板参数
template<int a,int b>
int fun2()
{
return a+b;
}
fun2<1,2>(); // 显示指定模板参数
template<T c,int a,int b>
int fun3(T c)
{
return (int)c +a+b;
}
fun3<int,11,22>(11);
template<unsigned L1,unsigned L2>
inline // 模板函数可以是内联函数,放在模板之后就行
int fun4(const char (&p)[L1],const char (&p2)[L2])
{
}
fun4("test","test2");// 系统会根据test,和test2自动推断出来L1和L2的长度,会计算结尾\0
模板定义不会导致编译器生产代码,当函数调用时,编译器才会生产特点版本的代码,编译器生产代码是需要找到函数体,所以一般模板函数都写在.h中
2、类模板
浮点型不能作为非类型模板参数,类类型也不行
template<class T>
class myvector
{
public:
typedef T* myiterator;
myvector(const myvector& tmp)
{
}
myvector& operator=(const myvector&)
{
}
void fun();
};
template<class T>
void myvector<T>::fun()
{
}
// 非类型类模板参数
template<class T,int T2>
class A
{
public:
void fun();
};
template<class T,int T2>
void A<T,T2>::fun()
{
}
A<int,22> s1;
3、typename使用场合
1、在模板定义中,其后模板参数时类型
template<typename T,int a,int b>
2、使用类的类型成员,需要typename来标识这是一个类型
template<class T>
class myvector
{
public:
typedef T* myiterator;
myvector(const myvector& tmp)
{
}
myvector& operator=(const myvector&)
{
}
public:
myiterator begin();
myiterator end();
void fun();
};
template<class T>
typename myvector<T>::myiterator myvector<T>::begin()
{
}
函数中
template<typename T>
typename T::size_type fun(const T& t)
{
if(t.empty())
{
return 0;
}
return t.size();
}
string s1 = "hello world";
string::size_type size = fun(s1);
4、函数指针做其他函数的参数
typedef int(*FunPtr)(int,int);
int my(int a,int b)
{
return a+b;
}
void fun(int a,int b,FunPtr my)
{
my(a,b);
}
fun(1,2,my);
5、函数模板趣味例子
1
typedef int(*FunPtr)(int,int);
int my(int a,int b)
{
return a+b;
}
template<typename T,typename F>
void fun(T a,T b,F my)
{
F(a,b);
}
fun(1,2,my);
2
class A
{
A()
{
cout<<"A构造函数执行"<<endl;
}
A(const A& tmp)
{
cout<<"拷贝构造函数"<<endl;
}
int operator()(int x,int y)const
{
return x+y;
}
}
template<typename T,typename F>
void fun(const T& a,const T& b,F my)
{
F(a,b);
}
// 会调用A的构造函数
// A的拷贝构造函数,是因为将a对象传递给函数fun时触发
A a;
fun(1,2,a);
6、using 使用
我们希望前面部分固定,后面通过指定
c++ 98实现这种需求的方式
template<typename ts>
struct wt
{
typedef std::map<std::string,ts> map_s_ts;
};
wt<int>::map_s_ts map1; //相当于定义了一个map<std::string,int> 类型
// c++ 11 实现
template<typename ts>
using str_map_t = std::map<std::string,ts>;
总结:using是新类型的别名
7、可变参模板
允许模板中含有0个,和多个,args我们称为一个包,多个参数可以为不同类型,
// 1
template<typename... T>
void myfunc(T... args)
{
cout<<sizeof...(args)<<endl; // 打印可变参个数
cout<<sizeof...(T)<<endl;
}
myfunc(); // 表示0个参数
myfunc(10,20,30)// 表示3个参数
// 2
template<typename U,typename... T>
void myfunc1(U& u,T&... args)
{
cout<<sizeof...(args)<<endl; // 打印可变参个数
}
myfunc1(10); // 至少有一个参数
2、包参数展开
void myfunc1()
{
cout<<"递归终止函数"<<endl;
}
// 一个参数,一个包,最适合参数包展开,通过递归调用,每次将进来的第一个参数给u,其他参数继续调用
template<typename U,typename... T>
void myfunc1(U& u,T&... args)
{
cout<<u<<endl;
myfunc1(args...);
}
myfunc1(10); // 至少有一个参数```