第3章 非类型模板参数:3.1 非类型类模板参数

Chapter 3: Nontype Template Parameters

第3章 非类型模板参数

For function and class templates, template parameters don’t have to be types. They can also be ordinary values. As with templates using type parameters, you define code for which a certain detail remains open until the code is used. However, the detail that is open is a value instead of a type. When using such a template, you have to specify this value explicitly. The resulting code then gets instantiated. This chapter illustrates this feature for a new version of the stack class template. In addition, we show an example of nontype function template parameters and discuss some restrictions to this technique.

对于函数模板和类模板,模板参数并不局限于类型。普通值也可以作为模板参数。在基于类型参数的模板中,你定了一些体具体细节未加确定的代码,直至代码被调用时这些细节才真正被确定。然而,我们面对的这些细节是值(value),而不是类型。当要使用基于值的模板时,你必须显式地指定这些值,才能够对模板进行实例化,并获得最终代码。在这章里,我们将使用一个新版本的stack类模板,来叙述这个特性。另外,我们还给出了一个非类型函数模板参数的例子,并且讨论了这一技术的某限制。

3.1 Nontype Class Template Parameters

3.1 非类型类模板参数

In contrast to the sample implementations of a stack in previous chapters, you can also implement a stack by using a fixed-size array for the elements. An advantage of this method is that the memory management overhead, whether performed by you or by a standard container, is avoided. However, determining the best size for such a stack can be challenging. The smaller the size you specify, the more likely it is that the stack will get full. The larger the size you specify, the more likely it is that memory will be reserved unnecessarily. A good solution is to let the user of the stack specify the size of the array as the maximum size needed for stack elements.

对比前一章stack例子的实现,你也可以使用元素数目固定的数组来实现stack。这个方法的优点是:无论是由你来亲自管理内存还是由标准容器来管理内存,都可以避免内存管理的开销。然而,决定一个栈(stack)的最佳容量是很困难的。如果你指定的容量太小,那么栈很可能会溢出。如果你指定的容量太大,那么很可能会造成不必要地浪费内存。一个好的解决方法是:让栈的用户自己指定数组的大小,并把它作为所需要的栈元素的最大个数。

To do this, define the size as a template parameter:

为了做到这一点,需要把数组大小定义为一个模板参数:

#include <array>
#include <cassert>
template<typename T, std::size_t Maxsize>
class Stack {
private:std::array<T, Maxsize> elems; // 元素
        std::size_t numElems; // 当前元素的个数
public:
    Stack(); // 构造函数
    void push(T const& elem); //压入元素
    void pop(); // pop element
    T const& top() const; // 返回栈顶元素
    bool empty() const { //返回栈是否为空
        empty
            return numElems == 0;
    } 
    std::size_t size() const { //返回当前元素的个数
            return numElems;
    }
};
template
<typename T, std::size_t Maxsize> Stack<T, Maxsize>::Stack() : numElems(0) //初始化时,元素个数为0 { // 什么也没做 }
template
<typename T, std::size_t Maxsize> void Stack<T, Maxsize>::push(T const& elem) { assert(numElems < Maxsize); elems[numElems] = elem; //追加元素 ++numElems; // 元素数量加1 } template<typename T, std::size_t Maxsize> void Stack<T, Maxsize>::pop() { assert(!elems.empty()); --numElems; //元素数量减1 }
template
<typename T, std::size_t Maxsize> T const& Stack<T, Maxsize>::top() const { assert(!elems.empty()); return elems[numElems - 1]; //返回最后一个元素 }

The new second template parameter, Maxsize, is of type int. It specifies the sizeof the internal array of stack elements:

Maxsize是新加入的第2个模板参数,类型为int。它指定了数组最多可包含的元素的个数:

template<typename T, std::size_t Maxsize>
class Stack {
private:
    std::array<T, Maxsize> elems; // elements
    …
};

In addition, it is used in push() to check whether the stack is full:

此外,在push()函数里进行了栈是否己满的检查:

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
}

To use this class template you have to specify both the element type and the maximum size:

为了使用这个类模板,你需要同时指定元素的类型和栈的最大容量:

#include "stacknontype.hpp"
#include <iostream>
#include <string>
int main()
{
    Stack<int, 20> int20Stack; // stack of up to 20 ints(可存储20个int元素的栈)
    Stack<int, 40> int40Stack; // stack of up to 40 ints
    Stack<std::string, 40> stringStack; // stack of up to 40 strings

    //操作可存储20个int元素的栈
    int20Stack.push(7);
    std::cout << int20Stack.top() << '\n';
    int20Stack.pop();

    // 操作可存储40个string元素的栈
    stringStack.push("hello"); 
    std::cout << stringStack.top() <<'\n';
    stringStack.pop();
}

Note that each template instantiation is its own type. Thus, int20Stack and int40Stack are two different types, and no implicit or explicit type conversion between them is defined. Thus, one cannot be used instead of the other, and you cannot assign one to the other.

可以看出,每个模板实例都具有自己的类型。因此,int20Stack和int40Stack属于两个不同的类型,而且这两种类型之间也不存在显式或隐式的类型转换。所以它们之间不能互相替换,更能互相赋值。

Again, default arguments for the template parameters can be specified:

同样,也可以为模板参数指定默认值:

template<typename T = int, std::size_t Maxsize = 100>
class Stack {
    …
};

However, from a perspective of good design, this may not be appropriate in this example. Default arguments should be intuitively correct. But neither type int nor a maximum size of 100 seems intuitive for a general stack type. Thus, it is better when the programmer has to specify both values explicitly so that these two attributes are always documented during a declaration.

然而,如果从优化设计的角度来看,这个例子并不适合使用默认值。默认值应该是直观上正确的值。但是对于栈的类型和大小而言,int类型和最大容量100从直观上看都不是正确的。因此,当程序员必须显式地指定这两个值时,最好是在设计文档中用一条声明来说明这两个属性(类型和最大容量)。

猜你喜欢

转载自www.cnblogs.com/5iedu/p/12710901.html