Effective C++条款条款42:了解typename的双重意义(Understand the two meanings of typename)

news2024/9/20 20:48:52

Effective C++条款条款42:了解typename的双重意义(Understand the two meanings of typename)

  • 条款42:了解typename的双重意义
    • 1、从属名称和非从属名称
    • 2、typename在traits机制中的运用
    • 3、牢记
  • 总结


《Effective C++》是一本轻薄短小的高密度的“专家经验积累”。本系列就是对Effective C++进行通读:

第7章:模板与泛型编程

在这里插入图片描述


条款42:了解typename的双重意义

  观察一下,下列template申明式中,class和typename有什么不同?

template<class T> class Widget;
template<typename T> class Widget;

  答案是:没有什么不同。当我们声明template类型参数,class和typename的意义完全相同。

1、从属名称和非从属名称

  但C++并不总是把class和typename视为等价。

  如,用来声明某种类型时。

  假设现在我们有一个模板,其接受一个STL容器类型,然后打印容器中的第二个元素的值,但是这个模板可能会产生错误(甚至不能通过编译)。

template<typename C>
void print2nd(const C& container)
{
    if (container.size() >= 2) {
        C::const_iterator iter(container.begin()); //初始化迭代器,绑定到第一个元素上
        ++iter;
        int value = *iter;
        std::cout << value;
    }
}

  这份代码中,我们特别强调两个局部变量:iter和value。这可以引出“嵌套从属名称”和“非从属名称”的概念:

从属名称:对于上面的局部变量iter来说,其是容器container的迭代器类型const_iterator,其实际上取决于template参数C的类型,因此我们称const_iterator为从属名称(意思就是:模板内的一个名称依赖于template的某个参数,那么其就是从属名称)。

  当从属名称属于class内时,我们称其为嵌套从属名称。因此上面的const_iterator就是一种嵌套从属名称。

  非从属名称:再观察value变量,其类型就是int。int是一个并不依赖任何template参数的名称,因此我们称int这样的名称为非从属名称。

  嵌套从属名称有可能导致解析(parsing)困难,举个例子:

  我们修改print2nd模板,假设在其中定义一个迭代器指针:

template<typename C>
void print2nd(const C& container)
{
    //...
    //const_iterator可能被编译器理解为C的static成员变量,x为一个变量,下面是两个变量的相乘
    C::const_iterator* x;
    //...
}

  好像我们声明x为一个local变量,它是个指针,指向一个C::const_iterator。但之所以我们会这样认为,是因为我们“已经知道”C::const_iterator是个类型?但如果C::const_iterator不是个类型,如果有个static变量恰好被命名为const_iterator,碰巧x是个全局变量呢?因此上面的代码可能会被编译器认为是两个变量在相乘。

  正确的做法是为嵌套从属名称加上一个关键字typename,这样可以显式地告诉编译器某种东西是一个类型,而不是其他东西。代码如下:

template<typename C>
void print2nd(const C& container)
{
    if (container.size() >= 2) {
        //使用typename,显式告诉编译器,const_iterator是一个类型
        typename C::const_iterator iter(container.begin());
        ...
    }
}

  typename只被用来嵌套从属类型名称;其他名称不该有它存在。例如下面这个函数模板,接受一个容器和一个“指向该容器”的迭代器:

template<typename C>
void f(const C& container,typename C::const_iterator iter);

typename必须作为嵌套从属类型名称的前缀词,这一规则的例外是:

当typename用来声明类型时,其不可以出现在两个地方:

  • ①基类的派生列表内的嵌套从属类型名称之前。

  • ②构造函数的成员初始化列中作为基类的修饰符。

我们假设Nested是基类中的一种类型。例如:

template<typename T>
class Derived :public Base<T>::Nested //此处不允许使用typename
{
public:
    explicit Derived(int) 
        :Base<T>::Nested(x)//此处不允许使用typename
    {
        typename Base<T>::Nested temp; //此处允许使用typename
    }
};

2、typename在traits机制中的运用

  假设我们正在写一个函数模板,其接受一个迭代器类型,而我们打算在函数中为迭代器所指的对象做一份副本。我们可以这样写:

template<typename IterT>
void workWithIterator(IterT iter)
{
    typename std::iterator_traits<IterT>::value_type temp(*iter);
    //...
}

  这里使用的iterator_traits<>模板类,其实一种traits类(参阅条款47)。相当于传递给其一个迭代器类型为其进行实例化,那么我们就可以通过其value_type萃取出迭代器所指的容器的类型。例如:

  • 如果IterT是list::iterator,那么value_type就代表string,temp的类型就是string。

  • 如果IterT是vector::iterator,那么value_type就代表int,temp的类型就是int。

  如果上面的代码比较复杂,那么我们还可以搭配typedef来使用。例如:

template<typename IterT>
void workWithIterator(IterT iter)
{
    typename std::iterator_traits<IterT>::value_type value_type; //为类型声明别名
    value_type temp(*iter); //使用类型定义变量
    //...
}

  关于typename的移植性问题:某些编译器接受typename,而可能有少数编译器不接受typename。因此其存在有移植性。

3、牢记

  • 声明template参数时,前缀关键字class和typename可互换。

  • 请使用关键字typename标识嵌套从属类型名称;但不得在base class lists(基类列)或member initialization list(成员初值列)内以它作为base class修饰符。

总结

期待大家和我交流,留言或者私信,一起学习,一起进步!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/432261.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1.17 从0开始学习Unity游戏开发--场景切换

前面的所有文章我们都在一个固定的游戏场景内进行开发&#xff0c;在最开始介绍场景这个概念的时候就已经提及&#xff0c;这个场景可以是一张地图&#xff0c;或者是一个对战房间等等&#xff0c;所以显然这个场景可以有多个&#xff0c;并且可以从一个场景切换到另外一个场景…

Collection接口

文章目录 1. Java集合框架概述2. Collection接口中15个方法的使用3. Iterator(迭代器)接口4. Connection子接口一&#xff1a;List4.1 List的实现类4.2 源码分析4.2.1 ArrayList源码分析4.2.2 LinkedList源码分析4.2.3 Vector源码分析 4.3 List接口中的常用方法 5. Collection子…

死锁---银行家算法例题

1、知识点 1.银行家算法使用的四个必要的数据结构是: 可用资源向量Available&#xff0c;最大需求矩阵Max&#xff0c;分配矩阵Allocation&#xff0c;需求矩阵Need。 2.银行家算法是不是破坏了产生死锁的必要条件来达到避免死锁的目的&#xff1f;若是&#xff0c;请简述破…

【数字 IC / FPGA】 有关建立/保持时间计算的思考

引言 最近准备一些数字IC的机试&#xff0c;刷到了一些有关静态时序分析的题目。有一些比较经典的题目&#xff0c;在这里整理分享一下。 有什么疑问可以在评论区交流~互相进步 双D触发器典型电路 假设时钟周期为Tcycle,Tsetup,Thold分别为触发器建立保持时间&#xff0c;为…

Mac OS挂载ext4硬盘

一、安装macFUSE Home - macFUSE 如下载macfuse-4.4.3dmg安装 安装过程可能会遇到“若要要启用系统扩展,您需要在恢复环境中修改安全性设置”的提示&#xff0c;如下图&#xff1a; 解决&#xff1a; 关机&#xff0c;直到键盘灯全灭了&#xff01; 再按住开机键&#xff0c…

机器视觉技术分享-彩色图像处理 含c++ ,python代码说明

彩色图像处理是指对彩色图像进行数字处理和分析的过程&#xff0c;其目的是提取图像的有用信息&#xff0c;改善图像质量&#xff0c;实现图像的增强、复原、分割、匹配、识别等功能。 针对彩色图像处理&#xff0c;可以采用以下一些常见的方法&#xff1a; 1. 颜色空间转换&…

简简单单认识一下Inscode

CSDN最新推出的Inscode服务是一个在线编程工具&#xff0c;旨在为开发者提供一个便捷的编写、运行和分享代码的环境&#xff0c;让开发者无需在本地搭建编程环境&#xff0c;即可快速编写和运行代码。 Inscode支持多种编程语言&#xff0c;包括Java、Python、C等&#xff0c;同…

C语言进阶之回调函数详解分析方法

一、函数指针 在讲回调函数之前&#xff0c;我们需要了解函数指针。 我们都知道&#xff0c;C语言的灵魂是指针&#xff0c;我们经常使用整型指针&#xff0c;字符串指针&#xff0c;结构体指针等。 int *p1; char *p2; STRUCT *p3; // STRUCT为我们定义的结构体 但是好像我…

PlumGPT【告别梯子,拥抱AI】

相信很多人苦于没有openai账号或者有着种种原因至今还没有使用过chatgpt&#xff0c;今天向大家推荐一个网站&#xff0c;在国内也可以任意方便使用&#xff0c;让你的办公效率最大化。 那就是PlumGPT&#xff1a;https://plumgpt.com/ PlumGPT&#xff08;国内版的chatgpt&a…

Mybatis分页实现

1. Rowbounds Rowbounds将所有符合条件的数据加载到内存&#xff0c;然后再实现逻辑切割。 Override public List<User> getAllUser() {RowBounds rowBounds new RowBounds(1, 2);return userMapper.getAllUser(rowBounds); }查询sql&#xff08;没有任何分页逻辑&…

【Redis】常用命令、各种数据结构及命令

目录 一、常见数据结构 二、常用命令 1、查询符合的所有key 2、删除key 3、判断key是否存在 4、给key设置过期时间 5、查看key的剩余过期时间 三、不同数据类型的操作命令 1、String 1.set 2.get 3.mset 4.mget 5.incr 6.incrby 7.incrbyfloat 8.setnx 9.se…

C++——内存分配与动态内存管理

文章目录&#x1f490;专栏导读&#x1f490;文章导读&#x1f337;C/C内存分布&#x1f33a;牛刀小试&#x1f33a;C语言动态内存管理&#x1f337;C动态内存管理&#x1f33a;对于内置类型&#x1f33a;对于自定义类型&#x1f337;operator new与operator delete函数&#x…

便携式明渠流量计有哪几种呢?

便携式明渠流量计有几种&#xff1f; 目前来说市面上是有两种&#xff0c;但最终的作用或者说是功能都是用来和明渠在线流量计做液位和流量比对的一种装置。 这两种有什么区别呢&#xff1f; 一种就是便携式明渠流量计磁致伸缩流量计&#xff0c;另一种就是便携式明渠超声波…

浅析EasyCVR基于B/S架构的技术特点与能力应用

EasyCVR基于云边端协同&#xff0c;可支持海量视频的轻量化接入与汇聚管理。平台兼容性强、拓展度高&#xff0c;可提供视频监控直播、视频轮播、视频录像、云存储、回放与检索、智能告警、服务器集群、语音对讲、云台控制、电子地图、平台级联等功能。 EasyCVR视频融合平台采用…

【MyBatis Plus】004 -- MyBatis Plus高级(AR、MP插件、自定义全局操作、自动填充、逻辑删除、枚举、代码生成器)

目录 1、ActiveRecord 1.1 开启AR之旅&#xff08;根据主键 id 进行查询&#xff09; 1.2 新增数据 1.3 更新操作 1.4 删除操作 1.5 根据条件查询 2、Oracle 主键 Sequence 2.1 部署Oracle环境 2.2 创建表以及序列 2.3 jdbc驱动包 2.4 修改application.properties 2.5 配置序列…

LC-1041 困于环中的机器人(模拟,快慢指针找环)

1041. 困于环中的机器人 难度中等148 在无限的平面上&#xff0c;机器人最初位于 (0, 0) 处&#xff0c;面朝北方。注意: 北方向 是y轴的正方向。南方向 是y轴的负方向。东方向 是x轴的正方向。西方向 是x轴的负方向。 机器人可以接受下列三条指令之一&#xff1a; "…

第一讲 初识Python

Python简介 Python&#xff08;英式发音&#xff1a;/ˈpaɪθən/&#xff1b;美式发音&#xff1a;/ˈpaɪθɑːn/&#xff09;是由荷兰人吉多范罗苏姆&#xff08;Guido von Rossum&#xff09;发明的一种编程语言&#xff0c;是目前世界上最受欢迎和拥有最多用户群体的编…

【Colab】Colab使用教程(跑本地文件)

文章目录前言一、上传本地文件二、Colaboratory使用1、连接2、调整文件3、运行文件三、未来可期前言 首先&#xff0c;自己想办法注册谷歌账号&#xff0c;本文不讲。 Colaboratory网址&#xff1a;https://colab.research.google.com/ 谷歌云端硬盘&#xff1a;https://dri…

【软件测试二】开发模型和测试模型,BUG概念篇

目录 1.软件的生命周期 2.瀑布模型 3.螺旋模型 4.增量&#xff0c;迭代 5.敏捷---scrum 1. 敏捷宣言 2.角色 6. 软件测试v模型 7.软件测试w模型 8.软件测试的生命周期 9.如何描述一个BUG 10.如何定义BUG的级别 11.BUG的生命周期 12.产生争执怎么办 1.软件的生命周期…

26岁转行网络安全,成功上岸安全开发!

前言 我是去年 9 月 22 日才正式学习网络安全的&#xff0c;之前在国营单位工作了 4 年&#xff0c;在长沙一个月工资只有 5000 块&#xff0c;而且看不到任何晋升的希望&#xff0c;如果想要往上走&#xff0c;那背后就一定要有关系才行。 而且国营单位的气氛是你干的多了&a…