在模板中使用非类型参数。

1. 非类型的类模板参数

在类的模板参数列表中,不一定是都是类型,或者适配器,也可以是一个数

我们可以通过非类型的类模板指定固定长度的栈,这样做的好处是避免动态的内存管理。下面的代码中,我们通过指定Maxsize来创建array从而进一步固化内存,限制栈的长度

template<typename T, std::size_t Maxsize>
class Stack {
    std::array<T, Maxsize> v;
    std::size_t n;
public:
    Stack();
    void push(const T&);
    void pop();
    const T& top() const;
    bool empty() const { return n == 0; }
    std::size_t size() const { return n; }
};

//使用
Stack<int, 20> intStack; // 20个int的Stack

当我们在使用的时候,需要针对Maxsize来做一些改善,比如在push时,就需要考虑上限问题,同时也要更新参数。

template<typename T, std::size_t Maxsize>
void Stack<T, Maxsize>::push(const T& x)
{
    assert(n < Maxsize); // 确定Stack未满
    v[n] = x;
    ++n;
}

2. 非类型的函数模板参数

你也可以在函数模板中直接定义参数,比如:

template<int val, typename T>
T addvalue(T x)
{
    return x+Val;
}

可以用来作函数的谓语,和lambda表达式一样(虽然我觉得并没有lambda好用)

std::vector<int> v{ 0, 1, 2};
std::vector<int> v2(3);
std::transform(v.begin(), v.end(), v2.begin(), addValue<1, int>);
for (auto x : v2) std::cout << x; // 123

在C++17中允许将非类型模板参数定义为auto,以接收任何允许作为非类型模板参数的类型。

emplate<typename T, auto Maxsize>
class Stack {
    std::array<T, Maxsize> v;
    size_type n;
public:
    using size_type = decltype(Maxsize);
    Stack();
    void push(const T&);
    void pop();
    const T& top() const;
    bool empty() const { return n == 0; }
    size_type size() const { return n; }
};

C++14中允许auto作为返回类型:

// 如果在类外定义size成员函数要写为
template <typename T, auto Maxsize>
typename Stack<T, Maxsize>::size_type Stack<T, Maxsize>::size() const
{
    return n;
}

// C++14中可写为
template <typename T, auto Maxsize>
auto Stack<T, Maxsize>::size() const
{
    return n;
}