深入解析C++非类型模板参数
目录
一、模板参数分类
二、非类型模板参数的应用
三、使用示例
四、非类型模板参数的限制
五、实际应用示例
六、非类型模板参数的默认值
1、基本语法
2、实际示例
1. 静态数组类设置默认大小
2. 使用示例
3、注意事项
一、模板参数分类
模板参数可分为两种主要类型:
-
类型形参:出现在模板参数列表中,跟在
class
或typename
关键字之后的参数类型名称 -
非类型形参:使用一个常量作为类或函数模板的参数,在模板中可将该参数当作常量使用
二、非类型模板参数的应用
非类型模板参数常用于需要编译期确定值的场景,例如实现静态数组类:
template<class T, size_t N> // N是非类型模板参数
class StaticArray {
public:size_t arraysize() const {return N;}T& operator[](size_t index) {return _array[index];}const T& operator[](size_t index) const {return _array[index];}private:T _array[N]; // 利用非类型模板参数指定静态数组的大小
};
三、使用示例
int main() {StaticArray<int, 10> a1; // 定义大小为10的整型静态数组cout << a1.arraysize() << endl; // 输出: 10StaticArray<double, 100> a2; // 定义大小为100的双精度静态数组cout << a2.arraysize() << endl; // 输出: 100return 0;
}
四、非类型模板参数的限制
-
允许的类型:
-
只允许使用整型家族(包括整数、字符、布尔等)
-
指针和引用在特定情况下也允许
-
-
不允许的类型:浮点数、类对象、字符串字面量
-
编译期要求:
-
非类型模板参数必须在编译期就能确定结果
-
因为编译器需要在编译阶段根据这些参数生成对应的类或函数
-
五、实际应用示例
标准库中的std::array
就是一个使用非类型模板参数的典型例子:
namespace bite {// 定义一个模板类型的静态数组template<class T, size_t N = 10> // 默认大小为10class array {public:T& operator[](size_t index) { return _array[index]; }const T& operator[](size_t index) const { return _array[index]; }size_t size() const { return N; } // 直接返回模板参数Nbool empty() const { return N == 0; }private:T _array[N];};
}
非类型模板参数为C++模板编程提供了更多灵活性,特别是在需要编译期常量的场景中非常有用。
六、非类型模板参数的默认值
非类型模板参数可以设置默认值,这与类型模板参数设置默认值的语法规则相同。
1、基本语法
template <class T, size_t N = 默认值> // 为非类型参数N设置默认值
class ClassName {// 类定义
};
2、实际示例
1. 静态数组类设置默认大小
template <class T, size_t N = 10> // 默认数组大小为10
class StaticArray {
public:size_t size() const { return N; }// ... 其他成员函数
private:T _array[N];
};
2. 使用示例
int main() {StaticArray<int> a1; // 使用默认大小10StaticArray<double, 20> a2; // 显式指定大小20cout << a1.size() << endl; // 输出: 10cout << a2.size() << endl; // 输出: 20return 0;
}
3、注意事项
-
默认参数规则:
-
与函数默认参数类似,从右向左设置默认值
-
如果某个模板参数有默认值,它右边的所有参数都必须有默认值
-
-
正确示例:
template <class T = int, size_t N = 10> // 正确 class A {};
-
错误示例:
template <class T = int, size_t N> // 错误:N没有默认值 class B {};
这种技术广泛用于需要编译期确定大小的容器类,是模板元编程中的重要技术之一。