C++ Templates:技巧性基础知识

关键字typename:
引入关键字typename是为了说明:模板内部的标识符可以是一个类型:
template <typename T>
class Myclass {
    typename T::SubType *ptr;
}

.template构造:
void printBitset (std::bitset<N> const& bs) {
    std::cout<< bs.template to_string< char, char_traits<char>, allocator<char> >();
}
.template告诉编译器.template后面的小于号是模板实参列表的起始符号。

使用this->:
对于那些在基类中声明,并且依赖于模板参数的符号(函数或变量等),应该在它们前面使用this->或者Base<T>::。
如果希望完全避免不确定性,可以限定模板中所有的成员访问。

成员模板和模板的模板参数:
通常,栈之间只有在类型完全相同时才能相互赋值,其中类型指的是元素的类型,即使这两种元素的类型之间存在隐式类型转换。‘
函数模板不支持模板的模板参数。
不同类型间赋值的解决办法(并加入模板的模板参数的完整版):

Code:
  1. #include <deque>  
  2. #include <stdexcept>  
  3. #include <memory>  
  4.   
  5. template <typename T,   
  6.     template <typename ELEM, typename = std::allocator<ELEM> > class CONT = std::deque> //模板的模板参数,其中类的两个模板参数是为了匹配std::deque的两个模板实参缺省模板参数(元素类型和内存分配器allocator)  
  7. class Stack {  
  8. private:  
  9.     CONT<T> elems;         // 由T来决定类模板中的元素的类型,实例化时可直接写为:Stack<int, std::vector> vStack  
  10.   
  11. public:  
  12.     void push(T const&);   // push element  
  13.     void pop();            // pop element  
  14.     T top() const;         // return top element  
  15.     bool empty() const {   // return whether the stack is empty  
  16.         return elems.empty();  
  17.     }  
  18.   
  19.     //在元素不同的栈之间相互赋值的重载operator=  
  20.     template<typename T2,   
  21.         template<typename ELEM2, typename = std::allocator<ELEM2> >class CONT2>  
  22.     Stack<T,CONT>& operator= (Stack<T2,CONT2> const&);  
  23. };  
  24.   
  25. template <typename T, template <typename,typenameclass CONT>  
  26. void Stack<T,CONT>::push (T const& elem)  
  27. {  
  28.     elems.push_back(elem);    // append copy of passed elem  
  29. }  
  30.   
  31. template<typename T, template <typename,typenameclass CONT>  
  32. void Stack<T,CONT>::pop ()  
  33. {  
  34.     if (elems.empty()) {  
  35.         throw std::out_of_range("Stack<>::pop(): empty stack");  
  36.     }  
  37.     elems.pop_back();         // remove last element  
  38. }  
  39.   
  40. template <typename T, template <typename,typenameclass CONT>  
  41. T Stack<T,CONT>::top () const  
  42. {  
  43.     if (elems.empty()) {  
  44.         throw std::out_of_range("Stack<>::top(): empty stack");  
  45.     }  
  46.     return elems.back();      // return copy of last element  
  47. }  
  48.   
  49. //在元素不同的栈之间相互赋值的重载operator=  
  50. template <typename T, template <typename,typenameclass CONT>  
  51.     template <typename T2, template <typename,typenameclass CONT2>  
  52. Stack<T,CONT>& Stack<T,CONT>::operator= (Stack<T2,CONT2> const& op2)  
  53. {  
  54.     if ((void*)this == (void*)&op2) {    // 自身赋值检测  
  55.         return *this;  
  56.     }  
  57.   
  58.     Stack<T2,CONT2> tmp(op2);        // 创建一份赋值栈的拷贝,以便使用top()和pop()从该拷贝中获取元素。  
  59.   
  60.     elems.clear();                   // 移除现有元素  
  61.     while (!tmp.empty()) {           // 拷贝所有元素  
  62.         elems.push_front(tmp.top());  
  63.         tmp.pop();  
  64.     }  
  65.     return *this;  
  66. }  

零初始化:
对于int、double或者指针等基本类型,应该显式地调用内建类型的缺省构造函数,并把缺省值设为0(或者false,对于bool类型而言)。比如调用int()我们就将获得缺省值0。
template <typename T>
void foo() {
    T x = T() ;
}

对于类模板,需要定义一个缺省构造函数,通过一个初始化列表来初始化类模板的成员。
template <typename T>
class Myclass {
private:
    T x;
public:
    Myclass() : x()
    ...
};

使用字符串作为函数模板的实参:

如果把字符串传递给函数模板的引用参数时,由于长度的区别,长度不同的字符串属于不同的数组类型,可以通过传递给非引用类型的参数来解决这个问题,但对于非引用类型的参数,在实参演绎的过程中,会出现数组到指针的类型转换。

根据不同的情况,对此类问题的解决方法:

  • 使用非引用参数,取代引用参数(然而,可能会导致无用的拷贝)
  • 进行重载,编写接收引用参数和非引用参数的两个重载函数(然而,可能会导致二义性)
  • 对具体类型进行重载(比如对std::string进行重载)
  • 重载数组类型,如:

    template <typename T, int N, int M>
    T const* max(T const (&a)[N], T const (&b)[M]) {
        return a < b ? b : a;
    }

  • 强制要求应用程序程序员使用显式类型转换。


小结:

  • 如果要访问依赖于模板参数的类型名称,应该在类型名称前添加关键字typename。
  • 嵌套类和成员函数也可以是模板。
  • 类模板也可以作为模板参数,称之为模板的模板参数。
  • 模板的模板实参必须精确地匹配。
  • 通过显式调用缺省构造函数,可以确保模板的变量和成员都已经用一个缺省值完成初始化,这种方法对内建类型的变量和成员也适用。
  • 对于字符串,在实参演绎过程中,当且仅当参数不是引用时,才会出现数组到指针的类型转换。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值