一、类模板的参数
1.默认参数
类模板的参数可以有默认值。但是指定默认值必须让有默认值的参数都放在最后。
下面是一个带有默认值的类模板:
//默认参数
template<typename T = char, typename U = int>
struct TC {
T val_1;
U val_2;
TC(T val1__, U val2__) :val_1(val1__), val_2(val2__) {}
};
由于模板有默认值,所以我们可以实例化模板的时候选择就更多了:
void Test1() {
TC<> t1('a', 1); //使用默认参数
TC<double> t2(1.0, 1);//第一个使用自定义参数,第二个使用默认参数
TC<double, float>t3(1.0, 1.0);//两个都使用自定义参数
}
2. 有依赖的默认参数
有时候,类模板的参数会依赖于之前的参数,比如指针(*),引用(&)等:
//有依赖的默认参数
template<typename T,typename U = T*> //U为T的指针
struct TC_ {
T val_1;
U val_2;
TC_(T val1__, U val2__) :val_1(val1__), val_2(val2__) {}
};
实例化时,传入两个参数分别表示值和指针。
void Test2() {
int x = 1;
int* ptr = nullptr;
TC_<int>t(x, ptr);
}
3.类模板声明默认参数
我们可以在类模板的声明就设置默认参数,这样我们在定义类模板的时候就不需要设置默认参数了。
声明可以是多次的,如下所示:
//在模板声明中指定默认参数
//类模板声明
template<typename T,typename U,typename V = int,typename W = char>
struct _TC;
//继续声明指定默认参数,之前声明过的默认参数不需要再次声明
template<typename T, typename U = char, typename V, typename W>
struct _TC;
//类模板定义
template<typename T, typename U, typename V , typename W >
struct _TC {
T val_1;
U val_2;
_TC(T val1__, U val2__) :val_1(val1__), val_2(val2__) {}
};
二、类型别名
在 C + + 11 C++11 C++11之前,我们使用 t y p e d e f typedef typedef对类型取别名,而 C + + 11 C++11 C++11引入了 u s i n g using using关键字,因此有以下两种方法:
//类型别名
typedef TC<int, float>IF_TC;
using ID_TC = TC<int, double>;
使用起来就是这样:
void Test3() {
IF_TC t1(0,0.0);//相当于TC<int,float>
ID_TC t2(1, 1.0); //相当于TC<int,double>
}
三、非类型模板参数
类模板的非类型模板参数和函数模板的非类型模板参数类似。
链接:参数类型
这里补充几点:
1.使用 s i z e _ t size\_t size_t来作为非类型模板参数
这里实现了一个数组类模板,传入参数,生成常量 s i z e _ t size\_t size_t个相同的元素:
//非类型模板参数
template<typename T,typename U = T ,size_t arrsize = 8>
struct TC__ {
T m_arr[arrsize];
U val;
//初始化arrsize大小的类型为T的数组,每个值为U类型数值
TC__(U _val):val(_val) {
for (int i = 0; i < arrsize; ++i) {
m_arr[i] = val;
}
}
//输出
void print();
};
因为 s i z e _ t size\_t size_t是编译是就确定的常量,所以可以作为非类型模板参数。
注意这里在类外实现的时候,传入的参数:
//类外实现
template<typename T,typename U,size_t arrsize>
void TC__<T, U, arrsize>::print() { //注意这里是arrsize不是size_t
for (int i = 0; i < arrsize; ++i) {
std::cout << m_arr[i] << " ";
}
std::cout << "\n";
}
注意传入的 a r r s i z arrsiz arrsiz,而不是 s i z e _ t size\_t size_t
2. 全局字符串常量数组作为非类型模板参数
因为字符串常量数组可以在编译时就可以确认了,所以可以作为参数:
template<const char* p>
struct _TC_ {
_TC_() {
std::cout << "_TC_的构造函数:p =" << p << "\n";
}
};
const char* ptr = "hello";
const char p[] = "world";
void Test5() {
//全局指针不能作为模板参数
//_TC_<ptr> t;
//全局字符串数组可以
_TC_<p> t;
//字符串常量也不行
//_TC_<"hello">t;
}
注意这里的全局指针和字符串常量都不能作为非类型参数传入,因为他们在编译时无法被直接确认,更多细节如下:
正如上面所说,在C++20及以上的版本已经可以支持
d
o
u
b
l
e
double
double和
f
l
o
a
t
float
float类型作为非类型模板参数了,而字符串还不可以,期待字符串的引入!