C++ template 学习归纳总结4

简介:

我们在这篇文章来说说typename关键字吧。这个关键字是在c++的标准化过程中引入的,目的在于说明template中的某个表示符号是一个类型,而不是其他的东西,看下面的代码:

template <typename T> 
class MyClass { 
   typename T::SubType * ptr; 
   … 
}; 

第一个typename我就不多说了,大家都知道,我来说一下第二个。他的意思是说T::SubType是class T内部定义的一个类型,从而ptr是一个指向【T:SubType类型】的指针。

如果在上面的代码中,没有第二个typename关键字的话,编译器会以为SubType是class Type的一个static成员。于是会被编译器理解为一个具体的东西,从而导致T::SubType * ptr 所表达的意思是两个数进行相乘。

关于这个知识的应用比较多的是STL中,比如:

#include <iostream> 

// print elements of an STL container 
template <typename T> 
void printcoll (T const& coll) 
{ 
    typename T::const_iterator pos;  // iterator to iterate over coll 
    typename T::const_iterator end(coll.end());  // end position 

    for (pos=coll.begin(); pos!=end; ++pos) { 
        std::cout << *pos << ' '; 
    } 
    std::cout << std::endl; 
} 

下面我们来看看另外一个有意思的问题。那就是”.template”,大家仔细查看下面的代码:

template<int N> 
void printBitset (std::bitset<N> const& bs) 
{ 
    std::cout << bs.template to_string<char,char_traits<char>, 
                                       allocator<char> >(); 
} 

大家注意到没有,。这个例子中的“.template”比较怪,但是如果没有他的话,那么编译器无法知道后面的“<”是模板参数的开始。而不是一个小于号。注意,只有当位于 点号之前的物件取决于某一个template parameter的时候,这种情况才会发生,以上的例子中,bs受控于N。也就是显式指明模板函数调用。可以理解为指名点姓的调用模板成员函数而非普通的。

结论是“.template”或者”->template”记号只能在templates中使用。而且他们必须紧跟在于template parameter相关的某个物件。

其实这里关于这个”.template”,笔者也没有搞懂,不知道哪位大牛搞懂了,麻烦指教一下,谢谢了。

下面我们来看看成员模板:

先看看下面的例子:

 

Stack<int> intStack1, intStack2;   // stacks for ints 
Stack<float> floatStack;           // stack for floats 
… 
intStack1 = intStack2;   // OK: stacks have same type 
floatStack = intStack1;  // ERROR: stacks have different types 

默认的赋值运算要求左右两边拥有相等的类型。但是如果把赋值运算定义为一个模板,就可以使得类型不同,但是元素可以隐式转换,比如:

template <typename T> 
class Stack { 
  private: 
    std::deque<T> elems;   // elements 

  public: 
    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 elems.empty(); 
    } 

    // assign stack of elements of type T2 
    template <typename T2> 
    Stack<T>& operator= (Stack<T2> const&); 
}; 

我们来实现它看看:关键代码如下:

template <typename T> 
 template <typename T2> 
Stack<T>& Stack<T>::operator= (Stack<T2> const& op2) 
{ 
    if ((void*)this == (void*)&op2) {    // assignment to itself? 
        return *this; 
    } 

    Stack<T2> tmp(op2);             // create a copy of the assigned stack 

    elems.clear();                  // remove existing elements 
    while (!tmp.empty()) {          // copy all elements 
        elems.push_front(tmp.top()); 
        tmp.pop(); 
    } 
    return *this; 
} 

下面我们测试一下啊:

Stack<int> intStack;     // stack for ints 
Stack<float> floatStack; // stack for floats 
… 
floatStack = intStack;   // OK: stacks have different types, 
                         //     but int converts to float 

当然这个运算并不改变stack和其元素的类型,赋值完成转换,floatstack返回的任然是float。但是这个技术并不是说任何两个类型都能进行赋值,比如下面的代码就不行:

Stack<std::string> stringStack;  // stack of ints 
Stack<float>       floatStack;   // stack of floats 
… 
floatStack = stringStack;  // ERROR: std::string doesn't convert to float 

你知道为什么了吗?

当然,和以前一样,你也可以在将内部容器的类型也参数化:

template <typename T, typename CONT = std::deque<T> > 
class Stack { 
  private: 
    CONT elems;            // elements 

  public: 
    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 elems.empty(); 
    } 

    // assign stack of elements of type T2 
    template <typename T2, typename CONT2> 
    Stack<T,CONT>& operator= (Stack<T2,CONT2> const&); 
}; 

此时的赋值运算实现代码为:

template <typename T, typename CONT> 
 template <typename T2, typename CONT2> 
Stack<T,CONT>& 
Stack<T,CONT>::operator= (Stack<T2,CONT2> const& op2) 
{ 
    if ((void*)this == (void*)&op2) {    // assignment to itself? 
        return *this; 
    } 

    Stack<T2> tmp(op2);              // create a copy of the assigned stack 

    elems.clear();                   // remove existing elements 
    while (!tmp.empty()) {           // copy all elements 
        elems.push_front(tmp.top()); 
        tmp.pop(); 
    } 
    return *this; 
} 
目录
相关文章
|
3月前
|
JavaScript 前端开发 编译器
模板编译template的背后,究竟发生了什么事?带你了解template的纸短情长
该文章深入探讨了Vue.js中从模板(template)到渲染(render)过程中的编译机制,解释了模板是如何被转化为可执行的渲染函数,并最终呈现为用户界面的全过程。
|
7月前
|
安全 程序员 编译器
【C/C++ 泛型编程 进阶篇 Type traits 】C++类型特征探究:编译时类型判断的艺术
【C/C++ 泛型编程 进阶篇 Type traits 】C++类型特征探究:编译时类型判断的艺术
502 1
|
7月前
|
自然语言处理 编译器 C语言
一文搞懂模板(template)
背景引入: 想象一下,我们要实现一个整数相加,浮点数相加的函数,如果按C语言的思路,我们需要写两个函数名不同的函数,来完成相加;如果C++语言,则可以通过函数重载的特性,写两个函数名相同,但参数列表不同的函数,来完成任务。
88 0
|
机器学习/深度学习 人工智能 自然语言处理
py基础知识点归纳总结(下)
py基础知识点归纳总结(下)
121 0
|
存储 Python 容器
py基础知识点归纳总结(上)
py基础知识点归纳总结(上)
110 0
|
JavaScript 前端开发
细读 ES6 | Class 下篇
ES6 中的继承。
136 0
|
前端开发
前端学习案例2-attribute
前端学习案例2-attribute
69 0
前端学习案例2-attribute
|
前端开发
前端学习案例3-attribute
前端学习案例3-attribute
75 0
前端学习案例3-attribute
|
前端开发
前端学习案例-ref的进阶用法2
前端学习案例-ref的进阶用法2
91 0
前端学习案例-ref的进阶用法2
|
前端开发
前端学习案例-ref的进阶用法1
前端学习案例-ref的进阶用法1
85 0
前端学习案例-ref的进阶用法1