代码改变世界

c++ template学习总结3

2012-03-08 10:03  Rollen Holt  阅读(670)  评论(1编辑  收藏  举报

和往常一样,先来看一段代码:

#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 
} 

接下来编写我们的测试函数:

#include <iostream> 
#include <string> 
#include <cstdlib> 
#include "stack4.hpp" 

int main() 
{ 
    try { 
        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); 
        std::cout << int20Stack.top() << std::endl; 
        int20Stack.pop(); 

        // manipulate stack of up to 40 strings 
        stringStack.push("hello"); 
        std::cout << stringStack.top() << std::endl; 
        stringStack.pop(); 
        stringStack.pop(); 
    } 
    catch (std::exception const& ex) { 
        std::cerr << "Exception: " << ex.what() << std::endl; 
        return EXIT_FAILURE;  // exit program with ERROR status 
    } 
} 

大家要注意int20Stack和int40Stack是两个不同的类型,他们是不能进行硬是或者显示的转换的。也不能够相互赋值。

你还可以为函数模板定义非型别参数:

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

当我们想把【函数】和某种操作作为参数传递的时候,就非常有用,比如在使用STL时,你可能有下面的代码:

std::transform (source.begin(), source.end(),  // start and end of source 
                dest.begin(),                  // start of destination 
                addValue<int,5>);              // operation 
有时候我们为了使得编译器推导的时候简单一些,可以使用:
std::transform (source.begin(), source.end(),  // start and end of source 
                dest.begin(),                  // start of destination 
                (int(*)(int const&)) addValue<int,5>);  // operation 

但是我们要注意,非类型模板参数也有自己的局限,通常来说他们只能是常整数,包括枚举,或者指向外部链接的指针。如果我们用浮点数或者class-type objects作为非类型模板参数是错误的:

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 

在这个例子中,s是一个外部连接的部件。