[Effective C++]条款42 typename

本文初发于 “天目中云的小站”,同步转载于此。

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

本条款中我们将了解typename的两种使用场景, 对typename的内涵及使用加深认知.

template声明式

在template的声明中, template<class T>template<typename T>都是被允许的, 这两种写法并没有任何差别, C++对这两种写法一视同仁, 但是在真正使用中, 作者还是建议在传入自定义类时用class, 在传入任意类型(包括int等)时用typename, 这样会增加代码的可读性.


针对嵌套从属类型名称的应用

先让我们认识嵌套从属类型名称的定义 :

  • 从属 : 依赖于某个template参数.
  • 嵌套 : 在class内呈嵌套状.
  • 从属嵌套类型名称 : 在class内呈嵌套状且依赖于某个template参数的类型名称.

我们通过下面的代码来理解 :

template<typename C>                           
void print2nd(const C& container)              
{                                               
  if (container.size() >= 2) {
     C::const_iterator iter(container.begin());  // 这里的C::const_iterator便是从属嵌套类型名称
     ++iter;                                    
     int value = *iter;                        
     std::cout << value;                        
  }
}

这段代码是无法通过编译的, 我们只有在前头加上typename才可以通过编译, 这是因为编译器起初并不确定C::const_iterator是一个类型名称, 所以当你明确指明其是一个类型名称之后, 编译器就可以正常运作了.

typename C::const_iterator iter(container.begin()); // 这样就可以了
  • 所以为什么编译器无法确定这是一个类型名称呢?

    其实是为了代码的严谨性, 我们举一个极端一点的例子 :

     C::const_iterator* x;
    

    当我们写下这样的代码时, 编译器并不知道const_iterator是C中的类型还是成员变量, 如果它是成员变量的话, 那么这其实是一个乘法运算式, *是乘号; 如果他是类型, 那么这其实就是一个定义式, *代表着指针. 这两种情况都完全合法, 因此需要程序员明确指出其究竟是什么才行.


两个例外

在一般情况下, typename必须作为嵌套从属类型名称的前缀词, 这一规则的例外是, typename不可出现在继承语句和初始值列表中, 这是C++中定死的, 没有必要去了解为什么, 记住就行.

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;      // 这里可以加
    ...                               
  }                                    
};

typename和typedef的组合使用

我们知道了typename会与嵌套从属类型名称绑定, 并且其实在一些情况下嵌套从属类型名称是很长的, 我们会习惯把typedef与typename组合, 将一个类型的书写长度缩短, 我们通过下面的例子了解 :

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

这是这个组合的经典用法, 在STL标准库中就有大量的使用.

这里通过typedef将typename std::iterator_traits<IterT>::value_type这个如此长的类型缩短到value_type, 不用想也一定会减少大量的代码量. 至于为什么会有这么长的类型, 这与iterator_traits的萃取功能有关, 简单来说就是IterT是一个迭代器类型,而iterator_traits可以根据iterT通过value_type萃取出迭代器所指向资源的真实类型T. 我们将在条款47中再作讨论这部分内容, 如果想深入学习的话也可以去STL源码剖析中研读.


请记住 :

  • typename作为template参数时, 和class意义完全相同.
  • typename必须作为嵌套从属类型名称的前缀词, 除非在继承语句和初始值列表中.
  • 将typedef和typename组合可以减小代码复杂度.

by 天目中云

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Uniapp Android 本地离线打包(详细流程)

一、简介 App 离线 SDK 暂时不支持 Kotlin&#xff0c;未来不清楚。 uniapp 提供了 云打包 与 本地打包 两种方案&#xff0c;云打包 需要排队且还有次数限制&#xff0c;本地打包 则就没有这些限制&#xff0c;而且会 本地打包 对开发 原生插件 有很大的帮助。 细节&#x…

记录一次电脑被入侵用来挖矿的过程(Trojan、Miner、Hack、turminoob)

文章目录 0、总结1、背景2、端倪3、有个微软的系统更新&#xff0c;就想着更新看看&#xff08;能否冲掉问题&#xff09;4、更新没成功&#xff0c;自动重启电脑5、风险文件&#xff08;好家伙命名还挺规范&#xff0c;一看名字就知道出问题了&#xff09;6、开机有一些注册表…

使用大语言模型的生物嵌入,后续应该会有很多类似文章出来!

生信碱移 语言模型嵌入 小编先前分享了使用ChatGPT基因嵌入做平替的顶刊文章GenePT&#xff0c;只需要在原本的领域工作上插入这类的GPT嵌入&#xff0c;就能够实现降维打击。 ▲ 对于GenePT或者嵌入感兴趣的铁子&#xff0c;可以点击查看上面这篇推文。 今天冲浪的时候又看…

如何在没有 iCloud 的情况下将联系人从 iPhone 传输到 iPhone

概括 近期iOS 13.5的更新以及苹果公司发布的iPhone SE在众多iOS用户中引起了不小的轰动。此外&#xff0c;不少变化&#xff0c;如暴露通知 API、Face ID 增强功能以​​及其他在 COVID-19 期间与公共卫生相关的新功能&#xff0c;吸引了 iPhone 用户尝试新 iPhone 并更新到最…

GitLab集成Runner详细版--及注意事项汇总【最佳实践】

一、背景 看到网上很多用户提出的runner问题其实实际都不是问题&#xff0c;不过是因为对runner的一些细节不清楚导致了误解。本文不系统性的介绍GitLab-Runner&#xff0c;因为这类文章写得好的特别多&#xff0c;本文只汇总一些常几的问题/注意事项。旨在让新手少弯路。 二、…

【从零开始入门unity游戏开发之——C#篇40】C#特性(Attributes)和自定义特性

文章目录 前言一、特性&#xff08;Attributes&#xff09;基本概念二、自定义特性1、自定义特性代码示例&#xff1a;2、应用自定义特性&#xff1a;3、解释3.1 **AttributeUsage 特性**3.2 特性的命名3.3 **构造函数**&#xff1a;3.4 **属性**&#xff1a; 4、使用反射获取特…

k8s基础(2)—Kubernetes-Namespace

一、Namespace概述 名字空间 在 Kubernetes 中&#xff0c;名字空间&#xff08;Namespace&#xff09; 提供一种机制&#xff0c;将同一集群中的资源划分为相互隔离的组。 同一名字空间内的资源名称要唯一&#xff0c;但跨名字空间时没有这个要求。 名字空间作用域仅针对带有…

iOS 逆向学习 - iOS Security Features:硬件与软件多重防护体系

iOS 逆向学习 - iOS Security Features&#xff1a;硬件与软件多重防护体系 iOS 安全特性全面解析&#xff1a;构筑多层次防御体系一、iOS 的硬件安全特性1. Secure Enclave&#xff08;安全隔区&#xff09;2. Hardware Root of Trust&#xff08;硬件信任根&#xff09;3. De…

计算机网络——数据链路层-流量控制和可靠传输

一、流量控制 流量控制是指由接收方及时控制发送方发送数据的速率&#xff0c;使接收方来得及接受。 • 停止等待流量控制 • 滑动窗口流量控制 1、停止—等待流量控制 停止-等待流量控制的基本原理是发送方每发出一帧后&#xff0c;就要等待接收方的应答信号&#xff…

Zookeeper是如何保证事务的顺序一致性的?

大家好&#xff0c;我是锋哥。今天分享关于【Zookeeper是如何保证事务的顺序一致性的?】面试题。希望对大家有帮助&#xff1b; Zookeeper是如何保证事务的顺序一致性的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Zookeeper 通过多个机制来保证事务的顺序一…

实际开发中,常见pdf|word|excel等文件的预览和下载

实际开发中,常见pdf|word|excel等文件的预览和下载 背景相关类型数据之间的转换1、File转Blob2、File转ArrayBuffer3、Blob转ArrayBuffer4、Blob转File5、ArrayBuffer转Blob6、ArrayBuffer转File 根据Blob/File类型生成可预览的Base64地址基于Blob类型的各种文件的下载各种类型…

Qt使用CMake编译项目时报错:#undefined reference to `vtable for MainView‘

博主将.h文件和.cpp文件放到了不同的文件目录下面&#xff0c;如下图所示&#xff1a; 于是构建项目的时候就报错了#undefined reference to vtable for MainView&#xff0c;这个是由于src/view目录下的CMake无法自动moc头文件导致的&#xff0c;需要手动moc include/view目录…

会员制电商创新:开源 AI 智能名片与 2+1 链动模式的协同赋能

摘要&#xff1a;本文聚焦于电商领域会员制的关键作用&#xff0c;深入探讨在传统交易模式向数字化转型过程中&#xff0c;如何借助开源 AI 智能名片以及 21 链动模式商城小程序&#xff0c;实现对会员数据的精准挖掘与高效利用&#xff0c;进而提升企业的营销效能与客户洞察能…

第27周:文献阅读及机器学习

目录 摘要 Abstract 一、文献阅读 发现问题 研究方法 CNN-LSTM DT SVR 创新点 案例分析 数据准备 模型性能 预测模型的实现 仿真实验及分析 二、LSTM 1、基本结构 2、具体步骤 3、举例说明 4、原理理解 总结 摘要 本周阅读文献《Short-term water qua…

【机器遗忘之UNSIR算法】2023年IEEE Trans期刊论文:Fast yet effective machine unlearning

1 介绍 年份&#xff1a;2023 期刊&#xff1a;IEEE Transactions on Neural Networks and Learning Systems 引用量&#xff1a;170 Tarun A K, Chundawat V S, Mandal M, et al. Fast yet effective machine unlearning[J]. IEEE Transactions on Neural Networks and Le…

Linux-----进程处理(waitpid,进程树,孤儿进程)

目录 waitpid等待 进程树 孤儿进程 waitpid等待 Linux中父进程除了可以启动子进程&#xff0c;还要负责回收子进程的状态。如果子进程结束后父进程没有正常回收&#xff0c;那么子进程就会变成一个僵尸进程——即程序执行完成&#xff0c;但是进程没有完全结束&#xff0c;其…

Docker- Unable to find image “hello-world“locally

Docker- Unable to find image “hello-world“locally 文章目录 Docker- Unable to find image “hello-world“locally问题描述一. 切换镜像1. 编辑镜像源2. 切换镜像内容 二、 检查设置1、 重启dockers2、 检查配置是否生效3. Docker镜像源检查4. Dokcer执行测试 三、自定义…

Android配件应用默认启动与USB权限申请区别

使用效果&#xff1a; USB配件授权演示 选择USB配件默认打开应用 申请USB配件使用权限

vue2框架配置路由设计打印单

业务效果: 查询出列表后&#xff0c;点击申请单按钮&#xff0c;弹出申请表格&#xff0c;可进行打印 后端实现 控制器、服务层等省略&#xff0c;关联查出数据提供接口给前端即可 <!--获取详细信息(用于申请单打印)--><select id"selectXxxxDetail" par…