26-2 模板非类型参数
在之前的课程中,你已经学习了如何使用模板类型参数来创建类型无关的函数和类。模板类型参数是一个占位符类型,它会替换作为参数传入的类型。
然而,模板类型参数并非唯一可用的模板参数类型。模板类和函数还可以使用另一种称为非类型参数的模板参数。
非类型参数
模板非类型参数是指参数类型已预定义,并替换为作为参数传入的 constexpr 值的模板参数。
非类型参数可以是以下任何一种类型:
- 整体类型
- 枚举类型
- 指向类对象的指针或引用
- 指向函数的指针或引用
- 指向类成员函数的指针或引用
- std::nullptr_t
- 浮点类型(自 C++20 起)整体类型
在以下示例中,我们创建一个非动态(静态)数组类,该类同时使用类型参数和非类型参数。类型参数控制静态数组的数据类型,而整数非类型参数控制静态数组的大小。
main.cpp
#include <iostream>
template <typename T, int size> // size is an integral non-type parameter
class StaticArray
{
private:
// The non-type parameter controls the size of the array
T m_array[size] {};
public:
T* getArray();
T& operator[](int index)
{
return m_array[index];
}
};
// Showing how a function for a class with a non-type parameter is defined outside of the class
template <typename T, int size>
T* StaticArray<T, size>::getArray()
{
return m_array;
}
int main()
{
// declare an integer array with room for 12 integers
StaticArray<int, 12> intArray;
// Fill it up in order, then print it backwards
for (int count { 0 }; count < 12; ++count)
intArray[count] = count;
for (int count { 11 }; count >= 0; --count)
std::cout << intArray[count] << ' ';
std::cout << '\n';
// declare a double buffer with room for 4 doubles
StaticArray<double, 4> doubleArray;
for (int count { 0 }; count < 4; ++count)
doubleArray[count] = 4.4 + 0.1 * count;
for (int count { 0 }; count < 4; ++count)
std::cout << doubleArray[count] << ' ';
return 0;
}
这段代码会生成以下结果:

上述示例的一个显著特点是,我们无需动态分配成员变量 m_array!这是因为对于 StaticArray 类的任何给定实例,size 都必须是 constexpr。例如,如果您实例化一个 StaticArray<int, 12>,编译器会将 size 替换为 12。因此,m_array 的类型为 int[12],可以进行静态分配。
标准库类 std::array 使用了此功能。当您分配一个 std::array<int, 5> 时,int 是类型参数,而 5 是非类型参数!
请注意,如果您尝试使用非 constexpr 值实例化模板的非类型参数,则不会生效:
template <int size>
class Foo
{
};
int main()
{
int x{ 4 }; // x is non-constexpr
Foo<x> f; // error: the template non-type argument must be constexpr
return 0;
}
在这种情况下,编译器会报错。


浙公网安备 33010602011771号