zoukankan      html  css  js  c++  java
  • C++模板(template)中typename

    1、typename关键字

      在声明template参数时, 前缀关键字class和typename可以互换,但在使用模板参数T的内部类型名称即嵌套从属名称时只能用typename。

      在C++标准化的过程中,引入关键字typename是为了说明:模板类型参数内部的标识符(associated type,常见于STL中的各种容器)也可以是一个类型:

      比如:

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

      这里介绍模板内参数名称的几个概念;

      从属名称(dependent names): 模板(template)内出现的名称, 依赖于某个模板(template)参数, 如T t;

      嵌套从属名称(nested dependent names):从属名称在class内呈嵌套装, 如T::const_iterator ci;

      非从属名称(non-dependent names): 不依赖任何template参数的名称, 如int value;
      
      任何时候在模板(template)中指涉一个嵌套从属类型名称, 需要在前一个位置, 添加关键字typename;

      如果不特定指出typename, 嵌套从属名称, 有可能产生解析(parse)歧义,可能会报错(GCC): error: need 'typename' before 'T::xxx' because 'T' is a dependent scope。

      比如:

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

      上述程序中,第二个typename被用来说明,SubType是定义与类T内部的一种类型,也就是associated type,因而,ptr是一个指向T::SubType类型的指针。如果不使用typename,T::SubType会被优先看做T的一个静态成员,也就是一个具体而变量或对象,于是,下面的表达式:

    T::SubType* ptr;

      编译器此时就无法辨别这SubType是什么,因为SubType可能是模板参数T内的一个static变量,ptr可以看成一个全局变量,此时代码会被看做类T的静态成员SubType和ptr的乘积,或者SubType可能是一个typedef比如

    class Class_T{
        typedef int SubType;
        ...
    };

      那上面代码转化过来就是这样:

    int *x;

     

    2、嵌套从属名称使用typename的几个场景

      a、模板内出现的名称如果依赖于某个模板参数,称之为从属名称(dependent name)。如果从属名称在class内呈嵌套状,我们称为嵌套从属名称(nested dependent name),举例如下:

    template<typename T>
    void print(const T & container)
    {
        T::const_iterator iter(container.begin());
        cout << *iter << endl;
        int value = *iter;
        return;
    }
    • 在上述代码中,iter 的类型是依赖于模板参数T的,因此被称为 从属名称;
    • 同理,value的类型是语言内置类型,不依赖于任何模板参数,因此被称为 非从属名称;
    • C++编译器在面对从属名称时,如果此时该从属名称又嵌套了其他类型,如此处的 iter就是T::const_iterator类型,这里的T::const_iterator 称为嵌套从属类型名称(嵌套于T类型,从属于模板参数T)

     或者

    template<typename T> // typename allowed (as is "class")
    void f(const T& container, // typename not allowed
            typename T::iterator iter); // typename required

      上述的T并不是嵌套从属类型名称 (它并非嵌套与任何“取决于模板参数”的东西内),所以声明container时并不需要以typename为前导。
    但T::iterator是个嵌套从属类型名称,所以必须以typename为前导。
      

      b、某个模板类里面typedef类型时,如果这个类型与模板参数T相关,就需要使用typename。即这样的形式:

    template <class T>
    class Test
    {
    public:
     typedef map<int, T> TEMPLATE_MAP; //TEMPLATE_MAP不需要typename,因为它不依赖其他的名称
     typedef map<int, T>::iterator TEMPLATE_MAP_ITER;  //error! 嵌套从属名称,依赖其他类的iterator名称
     typedef typename map<int, T>::iterator TEMPLATE_MAP_ITER; //yes 
    };

     

       c、例外:嵌套从属类型名称, 如果是基类列表(base class list)和成员初值列(member initialization list)中,不使用typename;

    /*
     * BInsertSort.cpp
     *
     *  Created on: 2014.4.17
     *      Author: Spike
     */
     
    #include <iostream>
    #include <vector>
     
    using namespace std;
     
    struct Number {
        Number(int x) {
            std::cout << "Number = " << x << std::endl;
        }
    };
     
    template<typename T>
    struct Base{
        typedef Number Nested;
    };
     
    template<typename T>
    class Derived: public Base<T>::Nested { //不用typename
    public:
        explicit Derived(int x) : Base<T>::Nested(x) { //不用typename
            typename Base<T>::Nested temp(7); //必须使用
        }
    };
     
    int main () {
        Derived<int> d(5);
     
        return 0;
    }

     

  • 相关阅读:
    优秀JS学习站点
    一些比较好的论坛、博客
    最全前端问题及答案总结[转]
    EDM制作要点
    前端技术-调试工具(下)
    前端技术-调试工具(上)
    smartJQueryZoom(smartZoom) 的使用方法
    修改博客园日历的默认样式
    smartJQueryZoom(smartZoom) 存在的兼容性BUG,以及解决方法
    javascript实战 : 简单的颜色渐变
  • 原文地址:https://www.cnblogs.com/Glucklichste/p/10700747.html
Copyright © 2011-2022 走看看