模板语法
一、函数模板
通用语法:
template<class 类型形参1, class 类型形参2, ...>
返回类型 函数模板名 (形参表) {...}
特化语法:
template<>
返回类型 函数模板名<类型实参1, 类型实参2, ...> (形参表) {...}
二、类模板
通用语法:
template<class 类型形参1, class 类型形参2, ...> class 类模板名 {...};
声明和实现分开:
template<class 类型形参1, class 类型形参2, ...> class 类模板名 {...};
template<class 类型形参1, class 类型形参2, ...>
返回类型 类模板名<类型形参1, 类型形参2, ...>::成员函数名 (形参表) {...}
特化语法:
template<> class 类模板名<类型实参1, 类型实参2, ...> {...};
声明和实现分开:
template<> class 类模板名<类型实参1, 类型实参2, ...> {...};
返回类型 类模板名<类型实参1, 类型实参2, ...>::成员函数名 (形参表) {...}
类模板成员函数特化:
template<>
返回类型 类模板名<类型实参1, 类型实参2, ...>::成员函数名 (形参表) {...}
=============================================================================================================
二、特例化
注意
c++模板机制规定 如果调用既能匹配普通函数,又能匹配模板函数,则优先匹配普通函数因此,当我们模板特例化的时候,会先匹配特例化的函数。
当前的模板不能满足需要 就需要特例化 :例如出现 char* 字符串的比较 strcmp strcpy
#include <iostream>
using namespace std;
template<typename T>class Com
{
public:
Com(T a,T b):m_a(a),m_b(b){}
int compare(void);
{
cout<<"m_a的类型"<<typeid(m_a).name()<<endl;
cout<<"m_b的类型"<<typeid(m_b).name()<<endl;
if(m_a < m_b) return -1;
if(m_a > m_b) return 1;
else return 0;
}
private:
T m_a;
T m_b;
};
template<>
int Com<char*>::compare(void){
cout<<"|char*|特化函数"<<endl;
if(strcmp(m_a,m_b)<0) return -1;
if(strcmp(m_a,m_b)>0) return -1;
return 0;
}
int main(void)
{
Com<string>c3("abcd","abcde");
cout<<c3.compare()<<endl;
Com<char*>c4("abcd","abcde");
cout<<c4.compare()<<endl;
return 0;
}
=============================================================================================================
三、模板的声明和实现类模板声明和实现分开、特例化
int compare(void);
template<typename T>
int Com<T>::compare(void)
{
cout<<"m_a的类型"<<typeid(m_a).name()<<endl;
cout<<"m_b的类型"<<typeid(m_b).name()<<endl;
if(m_a < m_b) return -1;
if(m_a > m_b) return 1;
else return 0;
}
函数模板声明和实现
template<typename T> int compare(T a,T b);
template<typename T>
int compare(T a,T b)
{
cout<<"a的类型"<<typeid(a).name()<<endl;
cout<<"b的类型"<<typeid(b).name()<<endl;
if(a < b) return -1;
if(a > b) return 1;
else return 0;
}
template<>
int Com<char*>::compare(void){
cout<<"|char*|特化函数"<<endl;
if(strcmp(m_a,m_b)<0) return -1;
if(strcmp(m_a,m_b)>0) return -1;
return 0;
}
函数模板特例化
template<> int compare<const char*>(const char*a,const char*b);
template<>
int compare<const char*>(const char*a,const char*b)
{
cout<<"a的类型"<<typeid(a).name()<<endl;
cout<<"b的类型"<<typeid(b).name()<<endl;
if(strcmp(a,b)<0) return -1;
if(strcmp(a,b)>0) return 1;
else return 0;
}
=============================================================================================================
四、其他说明1、局部特例化与最优匹配:编译器优先选择特化程度最高的版本
#include <iostream>
using namespace std;
template<typename T1,typename T2>
class Test
{
public:
Test(void){
cout<<"通用Test()"<<endl;
}
};
template<typename T1>class Test<T1,int>
{
public:
Test(void){
cout<<"特化Test()"<<endl;
}
};
template<>class Test<int,int>
{
public:
Test(void){
cout<<"完全特化Test()"<<endl;
}
};
int main(void)
{
Test<double,double> t1;
Test<string,int> t2;
Test<int,int> t3;
return 0;
}
通用Test()
特化Test()
完全特化Test()
2、局部特例化与最优匹配:编译器优先选择针对指针的特化版本
3、局部特例化与最优匹配:编译器优先选择参数匹配程度最高的特化版本
=============================================================================================================
五、非类型参数和缺省参数 非类型形参=内置类型形参
#include <iostream>
using namespace std;
template<typename T = string,size_t S=2>class Array
{
public:
Array(void):m_size(S){
for(size_t i=0;i<S;i++)
m_t[i] = i;
}
Array(T t[],size_t n):m_size(min(n,S)){
for(size_t i=0;i<m_size;i++)
m_t[i] = t[i];
}
void print(void){
for(size_t i=0;i<m_size;i++)
cout<<m_t[i]<<" ";
cout<<endl;
}
public:
T m_t[S];
size_t m_size;
};
int main(void)
{
Array<int,10>a1;
a1.print();
// size_t n;
// cin>>n;
// const size_t n = 1;
// Array<int,n>a2; // 整形数 非类型参数
Array<int,20>a3;
a3.print();
string str[] = {"aa","bb","cc"};
// Array<string>a4(str,sizeof str/sizeof str[0]);
Array<> a4(str,sizeof(str)/sizeof(str[0])); // 缺省参数
a4.print();
return 0;
}
非类型形参=内置类型形参:代表具体的一类(C++的标准数据类型的一种,如整型)
格式:由 标准数据类型 + 名字 组成
例如:template <int a, int b>,其中a和b都是非类型形参 或 如template<class T, int a>,T为类型参数,a为非类型参数
参数有三种情况:
1、整型或枚举类型
2、指针类型(包含普通对象的指针类型、函数指针类型、指向成员的指针类型)
3、引用类型(指向对象或指向函数的引用都是允许的)
有些常值不能作为有效的非类型实参,包括:
1、空指针常量
2、浮点型值
3、字符串
说明:
1、非类型形参在模板定义的内部是常量值,也就是说非类型形参在模板的内部是常量,或者说只能是右值,它们不能被取址,也不能被赋值
2、调用非类型模板形参的实参必须是一个常量表达式,或者是一个数,即它必须能在编译时计算出结果。
模板形参:一个模板作为另一个模板的参数
template<class A,class B,template<class C> class D>
class E{};
说明:
1、template<class C> class D 是一个模板。
2、定义一个模板E,其中有两个类型参数A和B,一个模板参数D。注意C有时候可以省略不写
模板参数使用说明:
1、首先要定义一个模板:用来实例化模板E的对象。
2、A和B可以是任意类型;但是D可以是程序员自己定义的,也可以是STL中的标准模板库
//首先定义一个普通的模板
template<class T>
class Array
{
//模板Array的成员
};
//定义一个模板Container,参数列表:一个类型为T,另一个模板类型Seq
template<class T, template<class> class Seq>//这里Seq前面的<>没有写参数名字
class Container
{
Seq<T> seq;
... ...
};
注意:注意Seq模板的声明并没有带模板参数的名字,因为这里我们不会用到这个参数,所以可以省略不写.
实例化:
Container<int, Array> container;
说明:模板第一个参数为int,第二个参数为STL中提供的模板(注意要使用实例化后的类型,因为这里参数必须是类型)用途:这样定义一个泛化的容器,容器里所存储的对象也是泛化