缺省参数
一、 常规缺省参数:
- 类型模板参数缺省值得规定:如果某个模板参数有缺省值,那么从这个有缺省值的模板参数开始,后面的所有模板参数都得有缺省值。举例如下所示:当 T 给定缺省值int时,U没有给定缺省值就会报错。
- 偏特化版本中的类型模板参数不能够设置缺省值。
#include <iostream>
#include <list>
#include <map>
#include <string>
using namespace std;
namespace _nmsp1
{
//TC的泛化版本
//template <typename T=int,typename U> //error
//template <typename T,typename U=int> //ok
//template <typename T,typename U> //ok
template <typename T=int,typename U=int> //ok
struct TC
{
TC()
{
cout<<"TC泛化版本的构造函数"<<endl;
}
void functest1()
{
cout<<"functest1() 泛化版本"<<endl;
}
};
//TC的特化版本
//template <typename T=char> //error ,偏特化版本中的类型模板参数不能够设置缺省值
template <typename T>
struct TC<T,int>
{
};
template <> //TC的全特化版本
struct TC<int,int>
{
};
}
int main()
{
_nmsp1::TC<> mytc5; //使用了缺省模板参数,所以<>中啥也不用提供
_nmsp1::TC<double> mytc6; //<>中第一个类型使用double, 第一个使用默认缺省参数
return 0;
}
二、 后面的模板参数依赖前面的模板参数
#include <iostream>
#include <list>
#include <map>
#include <string>
using namespace std;
namespace _nmsp2
{
template <typename T,typename U=T*>
struct TC
{
TC()
{
cout<<"TC() 泛化版本"<<endl;
}
~TC()
{
cout<<"~TC() 泛化版本"<<endl;
}
};
}
int main()
{
_nmsp2::TC<double> mytc5;
_nmsp2::TC<double,int> mytc6;
return 0;
}
二、 在模板声明中指定缺省参数
不建议使用这种语法,看到了能够看懂。
#include <iostream>
#include <list>
#include <map>
#include <string>
using namespace std;
namespace _nmsp3
{
//声明1,指定了 V 和 W
template <typename T,typename U,typename V=int,typename W=char>
struct TC;
//声明1,指定了 U
template <typename T,typename U=char,typename V,typename W> // 这里为什么可以不指定 V 和 W 的缺省值,因为在声明1中已经指定了。如果声明1中没有指定的话,就会报错
struct TC;
//定义泛化版本的TC
template <typename T,typename U,typename V,typename W> //相当于 U,V,W 都有缺省值了
struct TC
{
};
}
int main(int argc,char* argv[])
{
_nmsp3::TC<int> mytc; //相当于 U,V,W 都有缺省值了,<>里面只提供了一个int
return 0;
}
三、 类型别名
- 考虑到类型名比较长,所以一般用typedef(经典C++) 或者 using(C++11)给这些类型名起一个额外的别名来简化书写。
四、 非类型模板参数
- 数字是常量,类型一般为整形、指针类型。
#include <iostream>
#include <list>
#include <map>
#include <string>
using namespace std;
namespace _nmsp4
{
//template<typename T,typename U,size_t arrsize=8> //这种写法和下面等价
template<typename T,typename U,auto arrsize=8>
struct TC
{
public:
T m_arr[arrsize]; //编译的时候就确认数组的大小
void functest2();
};
//template<typename T,typename U,size_t arrsize> //注意这里实现的时候,arrsize 不能加缺省值
template<typename T,typename U,auto arrsize>
void TC<T,U,arrsize>::functest2()
{
cout<<"void TC<T,U>::functest2() 泛化版本"<<endl;
}
}
int main(int argc,char* argv[])
{
_nmsp4::TC<double,double> mytc;
for(size_t i=0;i<8;i++)
{
mytc.m_arr[i]=static_cast<double>(i);
}
for(size_t i=0;i<8;i++)
{
cout<<mytc.m_arr[i]<<endl;
}
_nmsp4::TC<double,double,18> mytc1;
mytc1.m_arr[17]=18.88;
cout<<mytc1.m_arr[17]<<endl;
return 0;
}
- 全局指针不能作为函数参数。但是全局数组是可以作为模板参数的。
#include <iostream>
#include <list>
#include <map>
#include <string>
using namespace std;
namespace _nmsp5
{
template<const char* p>
struct TC2
{
public:
TC2()
{
printf("call TC2(): p=%s\n",p);
}
};
const char* g_s="hello"; //全局指针
const char g_s1[]="hello"; //全局数组
}
int main(int argc,char* argv[])
{
//_nmsp5::TC2<_nmsp5::g_s> myct2; //compile error!
_nmsp5::TC2<_nmsp5::g_s1> myct21;
return 0;
}
- 字符串常量也无法作为模板参数。主要是因为:C++ 标准委员会有一些特殊的考虑,因为编译器可能会做优化,将相同的字符串链接到同一块地址空间上来。这个和不允许double,float等数组作为非类型模板参数是一样的原因。因为保存的是一个不精确的数字。