C++templates第三章非类型模版参数

对非类型模板参数,待定的不再是类型,而是某个数值。在使用这种模板时需要显式的指出待定数值的具体值,之后代码会被实例化。本章会通过一个新版的 Stack 类模板来展示这一特性。顺便也会介绍一下函数模板的非类型参数。

类模板的非类型参数

作为和之前章节中 Stack 实现方式的对比,可以定义一个使用固定尺寸的 array 作为容器的 Stack。这种方式的优点是可以避免由开发者或者标准库容器负责的内存管理开销。不过对不同应用,这一固定尺寸的具体大小也很难确定。如果指定的值过小,那么 Stack 就会很容易满。如果指定的值过大,则可能造成内存浪费。因此最好是让Stack 的用户根据自身情况指定 Stack 的大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <array> 
#include <cassert>
template<typename T, std::size_t Maxsize>
class Stack
{
private:
std::array<T, Maxsize> elems; // elements
std::size_t numElems; // current number of elements
public:
Stack(); // constructor
void push(T const& elem); // push element
void pop(); // pop element
T const& top() const; // return top element
bool empty() const
{
//return whether the stack is empty
return numElems == 0;
}
std::size_t size() const
{
//return current number of elements
return numElems;
}
};

第二个新的模板参数 Maxsize 是 int 类型的。通过它指定了 Stack 中 array 的大小

成员函数 push()也用它来检测 Stack 是否已满:

1
2
3
4
5
6
7
template<typename T, std::size_t Maxsize> 
void Stack<T,Maxsize>::push (T const& elem)
{
assert(numElems < Maxsize);
elems[numElems] = elem; // append element
++numElems; // increment number of elements
}

使用这个模板的时候,也要指出元素类型和stack的最大容量

Stack<int,20> int20Stack;

函数模板的非典型参数

同样也可以给函数模板定义非类型模板参数。比如下面的这个函数模板,定义了一组可以返 回传入参数和某个值之和的函数:

1
2
3
4
5
template<int Val, typename T> 
T addValue (T x)
{
return x + Val;
}

非类型模板参数的限制

使用非类型模板参数是有限制的。通常它们只能是整形常量(包含枚举),指向 objects/functions/members 的指针,objects 或者 functions 的左值引用,或者是 std::nullptr_t (类型是 nullptr)。

用auto作为非模板参数的类型

template<typename T, auto Maxsize>来代替第一小节的代码

总结

  • 模板的参数可以是类型也可以是数值
  • 不可以将浮点型或者class类型的对象用于非类型模板参数,使用字符串常量,临时变量和子对象的指针或引用也有一些限制
  • 通过使用关键词auto,可以使非类型模板参数的类型更为泛化