C++箴言:理解typename的两个含义

template

答案:没什么不同。在声明一个 template type parameter(模板类型参数)的时候,class 和 typename 意味着完全相同的东西。一些程序员更喜欢在所有的时间都用 class,因为它更容易输入。其他人(包括我本人)更喜欢 typename,因为它暗示着这个参数不必要是一个 class type(类类型)。少数开发者在任何类型都被允许的时候使用 typename,而把 class 保留给仅接受 user-defined types(用户定义类型)的场合。但是从 C++ 的观点看,class 和 typename 在声明一个 template parameter(模板参数)时意味着完全相同的东西。

然而,C++ 并不总是把 class 和 typename 视为等同的东西。有时你必须使用 typename。为了理解这一点,我们不得不讨论你会在一个 template(模板)中涉及到的两种名字。

假设我们有一个函数的模板,它能取得一个 STL-compatible container(STL 兼容容器)中持有的能赋值给 ints 的对象。进一步假设这个函数只是简单地打印它的第二个元素的值。它是一个用糊涂的方法实现的糊涂的函数,而且就像我下面写的,它甚至不能编译,但是请将这些事先放在一边——有一种方法能发现我的愚蠢:

template

我突出了这个函数中的两个 local variables(局部变量),iter 和 value。iter 的类型是 C::const_iterator,一个依赖于 template parameter(模板参数)C 的类型。一个 template(模板)中的依赖于一个 template parameter(模板参数)的名字被称为 dependent names(依赖名字)。当一个 dependent names(依赖名字)嵌套在一个 class(类)的内部时,我称它为 nested dependent name(嵌套依赖名字)。C::const_iterator 是一个 nested dependent name(嵌套依赖名字)。实际上,它是一个 nested dependent type name(嵌套依赖类型名),也就是说,一个涉及到一个 type(类型)的 nested dependent name(嵌套依赖名字)。

print2nd 中的另一个 local variable(局部变量)value 具有 int 类型。int 是一个不依赖于任何 template parameter(模板参数)的名字。这样的名字以 non-dependent names(非依赖名字)闻名。(我想不通为什么他们不称它为 independent names(无依赖名字)。如果,像我一样,你发现术语 “non-dependent” 是一个令人厌恶的东西,你就和我产生了共鸣,但是 “non-dependent” 就是这类名字的术语,所以,像我一样,转转眼睛放弃你的自我主张。)

nested dependent name(嵌套依赖名字)会导致解析困难。例如,假设我们更加愚蠢地以这种方法开始 print2nd:

这看上去好像是我们将 x 声明为一个指向 C::const_iterator 的 local variable(局部变量)。但是它看上去如此仅仅是因为我们知道 C::const_iterator 是一个 type(类型)。但是如果 C::const_iterator 不是一个 type(类型)呢?如果 C 有一个 static data member(静态数据成员)碰巧就叫做 const_iterator 呢?再如果 x 碰巧是一个 global variable(全局变量)的名字呢?在这种情况下,上面的代码就不是声明一个 local variable(局部变量),而是成为 C::const_iterator 乘以 x!当然,这听起来有些愚蠢,但它是可能的,而编写 C++ 解析器的人必须考虑所有可能的输入,甚至是愚蠢的。

直到 C 成为已知之前,没有任何办法知道 C::const_iterator 到底是不是一个 type(类型),而当 template(模板)print2nd 被解析的时候,C 还不是已知的。C++ 有一条规则解决这个歧义:如果解析器在一个 template(模板)中遇到一个 nested dependent name(嵌套依赖名字),它假定那个名字不是一个 type(类型),除非你用其它方式告诉它。缺省情况下,nested dependent name(嵌套依赖名字)不是 types(类型)。(对于这条规则有一个例外,我待会儿告诉你。)

记住这个,再看看 print2nd 的开头:

template

这为什么不是合法的 C++ 现在应该很清楚了。iter 的 declaration(声明)仅仅在 C::const_iterator 是一个 type(类型)时才有意义,但是我们没有告诉 C++ 它是,而 C++ 就假定它不是。要想转变这个形势,我们必须告诉 C++ C::const_iterator 是一个 type(类型)。我们将 typename 放在紧挨着它的前面来做到这一点:

template

通用的规则很简单:在你涉及到一个在 template(模板)中的 nested dependent type name(嵌套依赖类型名)的任何时候,你必须把单词 typename 放在紧挨着它的前面。(重申一下,我待会儿要描述一个例外。)

typename 应该仅仅被用于标识 nested dependent type name(嵌套依赖类型名);其它名字不应该用它。例如,这是一个取得一个 container(容器)和这个 container(容器)中的一个 iterator(迭代器)的 function template(函数模板):

template

C 不是一个 nested dependent type name(嵌套依赖类型名)(它不是嵌套在依赖于一个 template parameter(模板参数)的什么东西内部的),所以在声明 container 时它不必被 typename 前置,但是 C::iterator 是一个 nested dependent type name(嵌套依赖类型名),所以它必需被 typename 前置。

“typename must precede nested dependent type names”(”typename 必须前置于嵌套依赖类型名”)规则的例外是 typename 不必前置于在一个 list of base classes(基类列表)中的或者在一个 member initialization list(成员初始化列表)中作为一个 base classes identifier(基类标识符)的 nested dependent type name(嵌套依赖类型名)。例如:

template

这样的矛盾很令人讨厌,但是一旦你在经历中获得一点经验,你几乎不会在意它。

让我们来看最后一个 typename 的例子,因为它在你看到的真实代码中具有代表性。假设我们在写一个取得一个 iterator(迭代器)的 function template(函数模板),而且我们要做一个 iterator(迭代器)指向的 object(对象)的局部拷贝 temp,我们可以这样做:

template

不要让 std::iterator_traits

如果你觉得读 std::iterator_traits

template

value_type temp(*iter);

}

很多程序员最初发现 “typedef typename” 并列不太和谐,但它是涉及 nested dependent type names(嵌套依赖类型名)规则的一个合理的附带结果。你会相当快地习惯它。你毕竟有着强大的动机。你输入 typename std::iterator_traits

作为结束语,我应该提及编译器与编译器之间对围绕 typename 的规则的执行情况的不同。一些编译器接受必需 typename 时它却缺失的代码;一些编译器接受不许 typename 时它却存在的代码;还有少数的(通常是老旧的)会拒绝 typename 出现在它必需出现的地方。这就意味着 typename 和 nested dependent type names(嵌套依赖类型名)的交互作用会导致一些轻微的可移植性问题。

Things to Remember

·在声明 template parameters(模板参数)时,class 和 typename 是可互换的。

·用 typename 去标识 nested dependent type names(嵌套依赖类型名),在 base class lists(基类列表)中或在一个 member initialization list(成员初始化列表)中作为一个 base class identifier(基类标识符)时除外。

Original: https://www.cnblogs.com/chengxin1985/archive/2009/02/06/1385007.html
Author: 程鑫
Title: C++箴言:理解typename的两个含义

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/712691/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 如何读懂火焰图?

    软件的性能分析,往往需要查看 CPU 耗时,了解瓶颈在哪里。 火焰图(flame graph)是性能分析的利器。本文介绍它的基本用法。 一、perf 命令 让我们从 perf 命令…

    技术杂谈 2023年5月31日
    0116
  • jenkin部署(docker+gitlab)

    第一部分 安装部署 1.1 gitlab安装部署 最小配置 内存至少4g,系统内核至少在3.10以上 uname -r 可查看系统内核版本 默认docker已经安装 1、安装git…

    技术杂谈 2023年7月24日
    085
  • 核密度图的绘制

    转自:https://www.sohu.com/a/204161532_278730 我们先看一下别人家文章中的核密度图。 那么,怎么做出这样的图呢?这种核密度图到底想表达或表现什…

    技术杂谈 2023年5月31日
    0108
  • 【NFC】近距离无线通信概览

    近距离无线通信 (NFC) 是一组近距离无线技术,通常只有在距离不超过 4 厘米时才能启动连接。借助 NFC,您可以在 NFC 标签与 Android 设备之间或者两台 Andro…

    技术杂谈 2023年5月31日
    0117
  • 医院HIS(LIS)系统时钟同步(NTP网络时间服务器)技术详解

    医院HIS(LIS)系统时钟同步(NTP网络时间服务器)技术详解 医院HIS(LIS)系统时钟同步(NTP网络时间服务器)技术详解 京准电子科技官微——ahjzsz NTP网络时间…

    技术杂谈 2023年6月21日
    086
  • Python—类属性

    1. 属性 属性是属于对象的 数据或者 函数元素,通过句点标识符访问。 2. 类的数据属性 类的数据属性是指定义在类中的变量,不带self声明,这种变量是静态的(相当于C++中的静…

    技术杂谈 2023年7月11日
    087
  • Java-多线程入门

    前置知识 什么是进程,什么又是线程?咱不是讲系统,简单说下,知道个大概就好了。 进程:一个可执行文件执行的过程。线程:操作系统能够进行运算调度的 最小单位。它被包含在进程之中,是进…

    技术杂谈 2023年7月11日
    066
  • Firefox国外换为国内同步的服务器地址

    地址栏键入 about:config 点击 接受风险并同意 查找 identity 把右侧字符串包含 firefox.com 替换为 firefox.com.cn 即换为国内同步服…

    技术杂谈 2023年7月24日
    076
  • nf-Press —— 在线文档也可以加载组件和编写代码

    如果帮助文档可以加载组件,那么在介绍的同时就可以运行演示demo,是不是很酷?如果可以在线修改运行代码,那么是不是更容易理解? 上一篇 https://www.cnblogs.co…

    技术杂谈 2023年5月31日
    0104
  • 网络设备配置-7、配置单臂路由实现跨vlan通信

    一、前言 同系列前几篇:网络设备配置–1、配置交换机enable、console、telnet密码网络设备配置–2、通过交换机划分vlan网络设备配置&#8…

    技术杂谈 2023年7月11日
    099
  • 开发必备linux命令大全-稳赚不亏

    我们的服务一般都是在linux系统运行,因此了解一些关于linux命令是必须。接下来将一一详细介绍一些常用的linux的命令 文件操作 远程登录与操作 磁盘挂载 进程管理 启动和结…

    技术杂谈 2023年7月25日
    0102
  • 每天一个 HTTP 状态码 103

    103 Earyly Hints 是被用于在最终的 HTTP 消息前返回一些响应头… 103 Early Hints 103 Earyly Hints 是被用于在最终 …

    技术杂谈 2023年7月11日
    089
  • 23 种设计模式的通俗解释,虽然有点污,但是很正点

    01 工厂方法 追 MM 少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是 MM 爱吃的东西,虽然口味有所不同,但不管你带 MM 去麦当劳或肯德基,只管向服务员说「来四个鸡翅」就行了…

    技术杂谈 2023年7月10日
    086
  • 什么?Android上面跑Linux?

    前言 众所周知,现在程序员因为工作、个人兴趣等对各种系统的需求越来越大,部分人电脑做的还是双系统。其中,比较常见的有各种模拟器、虚拟机在windows上面跑Android、Linu…

    技术杂谈 2023年7月11日
    083
  • php连接mysql数据库大批量执行sql语句出现“Mysql server has gong away”错误

    php代码中加入以下代码 set_time_limit(3600); ini_set(‘memory_limit’, ‘1024M’); mysql客户端执行以下命令 set gl…

    技术杂谈 2023年7月11日
    069
  • 并发编程基础(上)

    从我开始写博客到现在,已经写了不少关于并发编程的了,差不多还有一半内容整个并发编程系列就结束了,而今天这篇博客是比较简单的,只是介绍下并发编程的基础知识( = =!其实,对于大神来…

    技术杂谈 2023年7月25日
    059
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球