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

==============================================================================
本文转自被遗忘的博客园博客,原文链接:http://www.cnblogs.com/rollenholt/archive/2012/03/08/2384871.html,如需转载请自行联系原作者
相关文章
|
8天前
|
C++ 开发者
C++学习之继承
通过继承,C++可以实现代码重用、扩展类的功能并支持多态性。理解继承的类型、重写与重载、多重继承及其相关问题,对于掌握C++面向对象编程至关重要。希望本文能为您的C++学习和开发提供实用的指导。
42 16
|
27天前
|
算法 网络安全 区块链
2023/11/10学习记录-C/C++对称分组加密DES
本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。
46 4
2023/11/10学习记录-C/C++对称分组加密DES
|
5月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
96 0
|
3月前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
3月前
|
Java 编译器 C++
c++学习,和友元函数
本文讨论了C++中的友元函数、继承规则、运算符重载以及内存管理的重要性,并提到了指针在C++中的强大功能和使用时需要注意的问题。
34 1
|
6月前
|
存储 安全 编译器
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
|
6月前
|
人工智能 分布式计算 Java
【C++入门 一 】学习C++背景、开启C++奇妙之旅
【C++入门 一 】学习C++背景、开启C++奇妙之旅
|
6月前
|
存储 自然语言处理 编译器
【C++入门 三】学习C++缺省参数 | 函数重载 | 引用
【C++入门 三】学习C++缺省参数 | 函数重载 | 引用
|
6月前
|
小程序 C++
【C++入门 二 】学习使用C++命名空间及其展开
【C++入门 二 】学习使用C++命名空间及其展开
|
6月前
|
存储 C++ 索引