三、非类型模板参数(Nontype Template Parameters)

对于函数模板和类模板,模板参数不一定必须是类型,也可是是常规的数值。当以类型(type)作为模板参数的时候,代码中未决定的是类型;当以一般的数字(non-type)作为模板参数的时候,代码中待定的内容便是某些数值。使用者这种模板必须要显示指定数值,模板才能实例化。

1、非类型类模板参数(Nontype Class Template Parameters)

之前章节中的列子中Stack类中使用vector或deque来存储元素。我们也可以使用一个固定大小的数值来存储元素。这么做的好处是在定义一个Stack对象的时候就分配了固定大小的内存空间,之后的元素操作就不再需要内存分配管理了。坏处是这个数值固定大小的设置比较困难,如果设置太小很数组容易满;如果设置太大又浪费内存空间。
一个可行方法是让使用者自己定义数组的最大空间。
如下:

// basics/stack4.hpp 

#include <stdexcept> 

template <typename T, int MAXSIZE> 
class Stack { 
  private: 
    T elems[MAXSIZE];        // elements 
    int numElems;            // current number of elements 
  public: 
    Stack();                 // constructor 
    void push(T const&);     // push element 
    void pop();              // pop element 
    T top() const;           // return top element 
    bool empty() const {     // return whether the stack is empty 
        return numElems == 0; 
    } 
    bool full() const {      // return whether the stack is full 
        return numElems == MAXSIZE; 
    } 
}; 

// constructor 
template <typename T, int MAXSIZE> 
Stack<T,MAXSIZE>::Stack () 
  : numElems(0)              // start with no elements 
{ 
    // nothing else to do 
}

template <typename T, int MAXSIZE> 
void Stack<T,MAXSIZE>::push (T const& elem) 
{ 
    if (numElems == MAXSIZE) { 
        throw std::out_of_range("Stack<>::push(): stack is full"); 
    } 
    elems[numElems] = elem;  // append element 
    ++numElems;              // increment number of elements 
} 

template<typename T, int MAXSIZE> 
void Stack<T,MAXSIZE>::pop () 
{ 
    if (numElems <= 0) { 
        throw std::out_of_range("Stack<>::pop(): empty stack"); 
    } 
    --numElems;              // decrement number of elements 
} 

template <typename T, int MAXSIZE> 
T Stack<T,MAXSIZE>::top () const 
{ 
    if (numElems <= 0) { 
        throw std::out_of_range("Stack<>::top(): empty stack"); 
    } 
    return elems[numElems-1];  // return last element 
} 

第二个新的模板参数MAXSIZE是int类型,它来指定stack对象所能容纳的最大元素个数。

使用这个Statck类模板的时候,需要指定元素类型和所能容纳的最大元素个数。如下:

Stack<int,20>         int20Stack;    // stack of up to 20 ints 
Stack<int,40>         int40Stack;    // stack of up to 40 ints 
Stack<std::string,40> stringStack;   // stack of up to 40 strings 
// manipulate stack of up to 20 ints 
int20Stack.push(7); 
int20Stack.pop(); 

// manipulate stack of up to 40 strings 
stringStack.push("hello"); 
std::cout << stringStack.top() << std::endl; 
stringStack.pop(); 

每一个模板的实例都有自己的类型。上述的例子中,“int20Stack”和“int40Stack”是两个不同的类型,因此这两个类型之间是不能相互隐式或显示类型转换,也不能相互替换,也不能相互赋值。
可以对模板参数设置默认值,如下:

template <typename T = int, int MAXSIZE = 100> 
class Stack { 
  … 
};

2、非类型函数模板参数(Nontype Function Template Parameters)

可以为函数模板定义非类型参数,如下:

template <typename T, int VAL> 
T addValue (T const& x) 
{ 
    return x + VAL; 
} 

3、非类型模板参数的局限(Restrictions for Nontype Template Parameters)

非类型模板有它的局限。通常它们只能是常数整数(constant integral values )包括枚举,或者是指向外部链接的指针。

float或者类类型的对象是不被允许的,如下:

template <double VAT>        // ERROR: floating-point values are not 
double process (double v)    //        allowed as template parameters 
{ 
    return v * VAT; 
} 

template <std::string name>  // ERROR: class-type objects are not 
class MyClass {              //        allowed as template parameters 
  … 
}; 

字符串常量不能作为模板参数,如下:

template <char const* name> 
class MyClass { 
  … 
}; 

MyClass<"hello"> x;   // ERROR: string literal "hello" not allowed 

全局指针也不能作为非类型的模板参数,如下:

template <char const* name> 
class MyClass { 
  … 
}; 

char const* s = "hello"; 

MyClass<s> x;         // ERROR: s is pointer to object with internal linkage 

但是如下代码是可以的:

template <char const* name> 
class MyClass { 
  … 
}; 

extern char const s[] = "hello"; 

MyClass<s> x;        // OK 

因为全局的char类型的数组已经被初始化为了”hello”,这是一个外部链接的对象。

4、总结

1、模板参数不仅仅可以是类型(type),还可以是值(value)
2、不能把float,class-type类型的对象,内部链接(internal linkage )对象,作为非类型模板参数。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值