详解C++模板编程中typename用法

typename的常规用法

typename在C++类模板或者函数模板中经常使用的关键字,此时作用和class相同,只是定义模板参数;在下面的例子中,该函数实现泛型交换数据,即交换两个数据的内容,数据的类型由_Tp决定。

template <typename _Tp>
inline void swap(_Tp& __a, _Tp& __b)
{
  _Tp __tmp = __a;
  __a = __b;
  __b = __tmp;
}

typename的第二个用法:修饰类型

限定名和非限定名

​ 限定名(qualified name),是限定了命名空间的名称。看下面这段代码,cout和endl是在命名空间std定义的,必须加上std::,使其为std::cout和std::endl,因此称其为限定名。

#include <iostream>

int main()
{
    std::cout << "Hello world!" << std::endl;
}

若在主函数前面使用using namespace std;或者在主函数内使用using std::cout;,然后使用时只用cout和endl,它们的前面不再有空间限定std::,所以此时的cout和endl叫做非限定名(unqualified name)。

#include <iostream>
using namespace std;

int main()
{
    using std::cout;
	using std::endl;
	cout << "Hello world!" << endl;
}

依赖名和非依赖名

依赖名(dependent name)是指依赖于模板参数的名称,而非依赖名(non-dependent name)则相反,指不依赖于模板参数的名称。看下面这段代码:

template <class T>
class MyClass
{
     int i;
     vector<int> vi;
     vector<int>::iterator vitr;

     T t;
     vector<T> vt;
     vector<T>::iterator viter;
 };

因为int是内置类型,前三个定义的类型在声明这个模板类时就已知,叫做非依赖名。然而对于接下来的三行定义,只有在模板实例化时才能知道它们的类型,因为它们都依赖于模板参数T。则T, vector<T>, vector<T>::iterator称为依赖名。

类作用域

在类外部访问类中的名称时,可以使用类作用域操作符,调用通常存在三种:静态数据成员、静态成员函数和嵌套类型:Metadata::value,Metadata::function,Metadata::ValueType;

 class Metadata {
     static int value;
     static int function();
     typedef std::string ValueType;
 };

下面来看一个例子:

template <class T>
void function()
{
	T::iterator *iter;
	.....
}

我们可能本意是想定义一个迭代器对象,例如我们如果用vector来实例化这个模板,那么iter
则应该是一个迭代器指针,但是,如果我们用下面这个类来实例化这个模板

class cType
{
    static int iterator;
    ...
};

/*
T::iterator *iter会被编译器解释为两个数相乘。事实上,C++编译器会采用第二种解释方法,即使iterator的确是一个类型名。
为了避免这种矛盾,当我们适用qualified dependent name的时候,需要用typename来指出这是一个类型名.即: typename T::iterator *iter;
typename 指出下面紧跟着的名称是一个类型
*/
template <typename T> class Y
{
    typename T::iterator *iter;
    typedef typename T::iterator iterator; //定义了Y::iterator类型名称
    ...
};

T::iterator这种名称,由于iterator具体是类型还是成员变量取决于T的类型实现,所以当我们知道T::iterator是个类型名称时,如果我们要使用这个类型名,前面必须要加typename.

typename使用规则

typename在下面情况下禁止使用:

  1. 模板定义之外,即typename只能用于模板的定义中
  2. 非限定类型,比如int,vector<int>之类
  3. 基类列表中,比如template <class T> class C1 : T::InterType不能在T::InterType前面加typename
  4. 构造函数的初始化列表中,如果类型是依赖于模板参数的限定名,那么在它之前必须加typename(除非是基类列表,或者在类的初始化成员列表中)。

到此这篇关于详解C++模板编程中typename用法的文章就介绍到这了,更多相关c++模板typename内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++模板元编程实现选择排序

    前言 模板在C++一直是比较神秘的存在. STL 和 Boost 中都有大量运用模板,但是对于普通的程序员来说,模板仅限于使用.在一般的编程中,很少会有需要自己定义模板的情况.但是作为一个有理想的程序员,模板是一个绕不过去的坎.由于C++标准的不断改进,模板的能力越来越强,使用范围也越来越广. 在C++11中,模板增加了 constexpr ,可变模板参数,回返类型后置的函数声明扩展了模板的能力:增加了外部模板加快了模板的编译速度:模板参数的缺省值,角括号和模板别名使模板的定义和使用变得更加的简

  • C++中模板(Template)详解及其作用介绍

    目录 概述 函数模板 类模板 模板类外定义成员函数 类库模板 抽象和实例 概述 模板可以帮助我们提高代码的可用性, 可以帮助我们减少开发的代码量和工作量. 函数模板 函数模板 (Function Template) 是一个对函数功能框架的描述. 在具体执行时, 我们可以根据传递的实际参数决定其功能. 例如: int max(int a, int b, int c){ a = a > b ? a:b; a = a > c ? a:c; return a; } long max(long a, l

  • C++模板类的用法

    本文实例讲述了C++模板类的用法,分享给大家供大家参考.具体实现方法如下: main.h头文件如下: 复制代码 代码如下: template <class T>  class actioncontainer  {  public:      //构造函数      actioncontainer()      {          m_nRedoPos = 0;          m_nUndoPos = 0;      }      //容器的接口函数      void add(T val

  • 深入理解c++模板中的class与typename

    前言 借来的<Effective STL>已经放在书架上很久了,想想这段时间不是在写lua做业务,就是在学安卓准备做业务,已经很久没有看过c++这个老伙计了.为了不把老本行丢了,也为了赶紧把书还回去给更多的人阅读.于是下定决心重头开始把它读完. 模板中使用class和typename的区别 还没翻几页,当看到这段代码的时候就楞了一下.印象中上次也是看到这里一下子没弄懂,还特地搜索过的.结果再来一遍的时候还是忘了.果然好记性不如烂笔头,赶紧写篇博客mark一下. 这里讲的是作者在声明模板的时候使

  • C++模板基础之函数模板与类模板实例详解

    泛型编程  如果让你编写一个函数,用于两个数的交换.在C语言中,我们会用如下方法: // 交换两个整型 void Swapi(int* p1, int* p2) { int tmp = *p1; *p1 = *p2; *p2 = tmp; } // 交换两个双精度浮点型 void Swapd(double* p1, double* p2) { double tmp = *p1; *p1 = *p2; *p2 = tmp; }  因为C语言不支持函数重载,所以用于交换不同类型变量的函数的函数名是不

  • 详解C++模板编程中typename用法

    typename的常规用法 typename在C++类模板或者函数模板中经常使用的关键字,此时作用和class相同,只是定义模板参数:在下面的例子中,该函数实现泛型交换数据,即交换两个数据的内容,数据的类型由_Tp决定. template <typename _Tp> inline void swap(_Tp& __a, _Tp& __b) { _Tp __tmp = __a; __a = __b; __b = __tmp; } typename的第二个用法:修饰类型 限定名和

  • 详解C++ 模板编程

    类型模板 类型模板包括函数模板和类模板,基本上是C++开发人员接触模板编程的起点. 下面代码演示了函数模板和类模板的使用方法: // 函数模板 template<typename T> T add(const T& a, const T& b) { return a + b; } // 类模板 template<typename T> class Point { private: T x[3]; ... }; 类型模板以template开始声明,尖括号内的typen

  • 详解C语言编程中预处理器的用法

    预处理最大的标志便是大写,虽然这不是标准,但请你在使用的时候大写,为了自己,也为了后人. 预处理器在一般看来,用得最多的还是宏,这里总结一下预处理器的用法. #include <stdio.h> #define MACRO_OF_MINE #ifdef MACRO_OF_MINE #else #endif 上述五个预处理是最常看见的,第一个代表着包含一个头文件,可以理解为没有它很多功能都无法使用,例如C语言并没有把输入输入纳入标准当中,而是使用库函数来提供,所以只有包含了stdio.h这个头文

  • 详解JavaScript异步编程中jQuery的promise对象的作用

    Promise, 中文可以理解为愿望,代表单个操作完成的最终结果.一个Promise拥有三种状态:分别是unfulfilled(未满足的).fulfilled(满足的).failed(失败的),fulfilled状态和failed状态都可以被监听.一个愿望可以从未满足状态变为满足或者失败状态,一旦一个愿望处于满足或者失败状态,其状态将不可再变化.这种"不可改变"的特性对于一个Promise来说非常的重要,它可以避免Promise的状态监听器修改一个Promise的状态导致别的监听器的行

  • 详解Java多线程编程中的线程同步方法

    1.多线程的同步: 1.1.同步机制: 在多线程中,可能有多个线程试图访问一个有限的资源,必须预防这种情况的发生.所以引入了同步机制:在线程使用一个资源时为其加锁,这样其他的线程便不能访问那个资源了,直到解锁后才可以访问. 1.2.共享成员变量的例子: 成员变量与局部变量: 成员变量: 如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作,这多个线程是共享一个成员变量的. 局部变量: 如果一个变量是局部变量,那么多个线程对同一个对象进行操作,每个线程都会有一个该局部变量的拷贝.他们

  • 详解Java设计模式编程中的策略模式

    定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换. 类型:行为类模式 类图: 策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换.在前面说过的行为类模式中,有一种模式也是关注对算法的封装--模版方法模式,对照类图可以看到,策略模式与模版方法模式的区别仅仅是多了一个单独的封装类Context,它与模版方法模式的区别在于:在模版方法模式中,调用算法的主体在抽象的父类中,而在策略模式中,调用算法的主体则是封装到了封装类Context中

  • 详解Python核心编程中的浅拷贝与深拷贝

    一.问题引出浅拷贝 首先看下面代码的执行情况: a = [1, 2, 3] print('a = %s' % a) # a = [1, 2, 3] b = a print('b = %s' % b) # b = [1, 2, 3] a.append(4) # 对a进行修改 print('a = %s' % a) # a = [1, 2, 3, 4] print('b = %s' % b) # b = [1, 2, 3, 4] b.append(5) # 对b进行修改 print('a = %s'

  • 详解Java多线程编程中LockSupport类的线程阻塞用法

    LockSupport是用来创建锁和其他同步类的基本线程阻塞原语. LockSupport中的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程,而且park()和unpark()不会遇到"Thread.suspend 和 Thread.resume所可能引发的死锁"问题. 因为park() 和 unpark()有许可的存在:调用 park() 的线程和另一个试图将其 unpark() 的线程之间的竞争将保持活性. 基本用法 LockSupport 很类似于二元信号

  • 详解Java多线程编程中互斥锁ReentrantLock类的用法

    0.关于互斥锁 所谓互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5之前, 我们通常使用synchronized机制控制多个线程对共享资源的访问. 而现在, Lock提供了比synchronized机制更广泛的锁定操作, Lock和synchronized机制的主要区别: synchronized机制提供了对与每个对象相关的隐式监视器锁的访问, 并强制所有锁获取和释放均要出现在一个块结构中, 当获取了多个锁时, 它们必须以相反的顺序释放. synchronized机制对锁的释放是

  • 详解Java设计模式编程中的依赖倒置原则

    定义: 高层模块不应该依赖低层模块,二者都应该依赖其抽象:抽象不应该依赖细节:细节应该依赖抽象. 问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成.这种场景下,类A一般是高层模块,负责复杂的业务逻辑:类B和类C是低层模块,负责基本的原子操作:假如修改类A,会给程序带来不必要的风险. 解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率.          依赖倒置原则基于这样一个事实:

随机推荐