首页/新闻资讯/正文详情

Effective C++ 学习笔记 条款47 请使用traits classes表现类型信息

发布时间:2026/9/27 22:48:45 来源:云帆数科 栏目:资讯中心
Effective C++ 学习笔记 条款47 请使用traits classes表现类型信息
STL 主要由容器、迭代器和算法的模板构成但它也有一些工具模板。其中一个叫做 advance。advance 将指定的迭代器移动指定的距离从概念上讲advance 只是执行 iter d但 advance 不能那样实现因为只有随机访问迭代器才支持 操作。功能较弱的迭代器类型必须通过迭代地应用 或 – 共 d 次来实现 advance。嗯你不记得 STL 迭代器类别了没问题我们简单回顾一下。迭代器共有五类对应它们支持的操作。输入迭代器只能向前移动一次只能移动一步只能读取所指内容而且只能读取一次。它们模仿的是输入文件中的读指针C 标准库中的 istream_iterator 就是这一类别的典型代表。输出迭代器与之类似只不过面向输出它们只能向前移动一次只能移动一步只能写入所指内容而且只能写入一次。它们模仿的是输出文件中的写指针ostream_iterator 是这一类别的典型代表。这是功能最弱的两个迭代器类别。因为输入和输出迭代器只能向前移动且对所指内容至多读或写一次所以它们只适用于单遍算法。功能更强的一类迭代器是前向迭代器。这类迭代器能做输入和输出迭代器能做的一切此外还能对所指内容多次读取或写入。这使它们适用于多遍算法。STL 不提供单向链表但有些库提供了通常叫 slist这类容器的迭代器就是前向迭代器。TR1 哈希容器参见条款54的迭代器也可能属于前向类别。双向迭代器在前向迭代器的基础上增加了向后移动的能力也能向前移动。STL 的 list 的迭代器属于这一类别set、multiset、map 和 multimap 的迭代器也是。功能最强大的迭代器类别是随机访问迭代器。这类迭代器在双向迭代器的基础上增加了执行“迭代器算术”的能力即在常数时间内向前或向后跳跃任意距离。这种算术类似于指针算术这并不令人意外因为随机访问迭代器是以内置指针为模型而内置指针可以作为随机访问迭代器使用。vector、deque 和 string 的迭代器都是随机访问迭代器。对于这五种迭代器类别C 在标准库中都有一个“标签结构体”来标识它们这些结构体之间的继承关系是有效的 is-a 关系参见条款32确实所有前向迭代器同时也是输入迭代器等等。我们很快就会看到这种继承的用处。不过回到 advance。鉴于迭代器能力各不相同实现 advance 的一种方式是采用“最低公分母”策略用一个循环反复递增或递减迭代器。然而这种做法会花费线性时间。随机访问迭代器支持常数时间的迭代器算术我们希望在具备这种能力时加以利用。我们真正想做的是像这样实现 advance这需要能够判断 iter 是否是随机访问迭代器而这又需要知道它的类型 IterT 是否是随机访问迭代器类型。换句话说我们需要获取某个类型的信息。这正是 traits 让你做的事它们允许你在编译期间获取关于类型的信息。Traits 不是 C 中的关键字也不是预定义构件它们是 C 程序员遵循的一种技术和约定。这种技术的要求之一是它必须对内置类型和对用户自定义类型同样有效。例如如果 advance 用一个指针比如 const char*和一个 int 调用advance 必须能工作但这就意味着 traits 技术必须适用于像指针这样的内置类型。traits 必须适用于内置类型这意味着把信息嵌套在类型内部之类的做法行不通因为没有办法把信息嵌套在指针内部。因此某个类型的 traits 信息必须位于该类型外部。标准做法是把它放进一个模板以及该模板的一个或多个特化中。对于迭代器标准库中的这个模板名为 iterator_traits如你所见iterator_traits 是一个结构体。按照惯例traits 总是以结构体来实现。另一个惯例是用于实现 traits 的结构体被称为——这不是我编的——traits 类。iterator_traits 的工作方式是对于每一种类型 IterT在结构体iterator_traitsIterT中声明一个名为 iterator_category 的 typedef。这个 typedef 标识出 IterT 的迭代器类别。iterator_traits 分两部分实现这一点。首先它施加了这样的要求任何用户自定义迭代器类型都必须包含一个名为 iterator_category 的嵌套 typedef用于标识适当的标签结构体。例如deque 的迭代器是随机访问迭代器因此 deque 迭代器的类大致如下然而list 的迭代器是双向迭代器所以它们会这样做iterator_traits 只是鹦鹉学舌般地把迭代器类的嵌套 typedef 回传出来这对用户自定义类型很有效但对作为指针的迭代器则完全行不通因为根本不存在带嵌套 typedef 的指针。iterator_traits 实现的第二部分就是来处理作为指针的迭代器。为了支持这类迭代器iterator_traits 为指针类型提供了一个部分模板特化。指针的行为如同随机访问迭代器所以 iterator_traits 为它们指定的就是这一类别至此你已经知道如何设计和实现一个 traits 类1.确定你希望提供的关于类型的某些信息例如对迭代器而言它们的迭代器类别。2.选择一个名称来标识该信息例如 iterator_category。3.提供一个模板以及一组特化例如 iterator_traits其中包含你想支持的那些类型的信息。有了 iterator_traits——实际上是 std::iterator_traits因为它是 C 标准库的一部分——我们就可以改进 advance 的伪代码尽管这看起来很有前景但这并不是我们想要的。一方面它会导致编译问题我们将在条款48中探讨这一点但眼下还有一个更根本的问题需要考虑。IterT 的类型在编译期间是已知的所以iterator_traitsIterT::iterator_category也能在编译期间确定。然而这个 if 语句是在运行时求值的。为什么要在运行时做我们在编译时就能做的事情呢这名副其实地浪费时间还会让我们的可执行文件膨胀。我们真正想要的是一个针对类型的条件构造即 if…else 语句并且在编译期间求值。碰巧C 已经有办法获得这种行为那就是重载。当你重载某个函数 f 时你为不同的重载指定不同的参数类型。当你调用 f 时编译器根据你传入的实参挑选最佳重载。编译器实际上是在说“如果这个重载与传入内容最匹配就调用这个 f如果另一个重载最匹配就调用它如果第三个最匹配就调用它”等等。看到了吗这就是一个针对类型的编译期条件构造。要让 advance 按我们期望的方式工作我们只需创建两个重载函数把 advance 的“内脏”放进去并声明每个函数接受不同类型的 iterator_category 对象。我用 doAdvance 来命名这些函数由于 forward_iterator_tag 继承自 input_iterator_tag为 input_iterator_tag 编写的 doAdvance 版本也能处理前向迭代器。这正是各种 iterator_tag 结构体之间采用继承关系的动机所在事实上这也是所有 public 继承的部分动机为基类类型编写的代码同样适用于派生类类型。advance 的规范允许随机访问迭代器和双向迭代器使用正距离和负距离但如果你试图让前向迭代器或输入迭代器移动负距离行为就是未定义的。我检查过的那些实现只是简单地假定 d 非负因此如果传入了负距离就会进入一个非常长的循环一路“倒数”到零。在上面的代码中我改为展示抛出一个异常。两种实现都是有效的。这就是未定义行为的诅咒你无法预测会发生什么。有了 doAdvance 的这些重载版本advance 需要做的就只是调用它们并额外传入一个适当迭代器类别类型的对象这样编译器就会利用重载解析来调用正确的实现现在我们可以总结一下如何使用 traits 类1.创建一组重载的“工人”函数或函数模板例如 doAdvance它们在一个 traits 参数上有所不同。根据传入的 traits 信息来实现每个函数。2.创建一个“主”函数或函数模板例如 advance它调用这些工人函数并传入由 traits 类提供的信息。traits 在标准库中被广泛使用。当然有 iterator_traits它除了 iterator_category 之外还提供关于迭代器的另外四条信息其中最有用的当属 value_type——条款42展示了它的一个使用示例。还有 char_traits它保存关于字符类型的信息以及 numeric_limits它提供关于数值类型的信息比如它们可表示的最小值和最大值等numeric_limits 这个名字有点出人意料因为更常见的惯例是 traits 类以“traits”结尾但它就叫 numeric_limits所以我们也就用 numeric_limits 这个名字。TR1参见条款54引入了一大批新的 traits 类用于提供关于类型的信息包括is_fundamentalTT 是否为内置类型、is_arrayTT 是否为数组类型和is_base_ofT1, T2T1 是否与 T2 相同或者是 T2 的基类。总的来说TR1 为标准 C 添加了 50 多个 traits 类。切记1.traits 类使得关于类型的信息在编译期间可用。它们通过模板和模板特化来实现。2.与重载结合使用时traits 类使得对类型执行编译期 if…else 测试成为可能。

相关推荐

电商商品图出图周期与工时参数对照:实拍流程与AI生成
电商商品图出图周期与工时参数对照:实拍流程与AI生成

截至 2026 年 9 月,电商商品图的出图周期可以用几组可核对的参数描述:10 个 SKU 走传统实拍完整出图耗时 3~5 个工作日,单批次需 1 名拍摄 1 名美工全程投入,多平台规格适配单次约 2~4 小时;走 AI 生成路径&#xff0… · 2026/9/27 22:48:45

保姆级:从 0 到 1 用 Electron 封装 DeepSeek Harness
保姆级:从 0 到 1 用 Electron 封装 DeepSeek Harness

承接上篇:这个桌面应用是 AI 从规划到实现全程完成的,本篇把可复现的落地步骤完整贴出来——从同级 clone 到 2 个补丁到跑通,附 Windows 受限网络三坑。 上一篇《让AI把 DeepSeek Harness 做成桌面应用》,我讲了架构——进程内 H… · 2026/9/27 22:48:45

ECC 编程智能体嵌入式适配实战:ESP32/RK3588 驱动开发提效 60%+ 指南
ECC 编程智能体嵌入式适配实战:ESP32/RK3588 驱动开发提效 60%+ 指南

一、技术背景:为什么嵌入式开发者需要 ECC 编程智能体?1.1 嵌入式开发的核心痛点做过嵌入式开发的工程师都有类似经历:查几十页的 datasheet 配置寄存器,一个位写错要调试半天不同芯片的外设驱动逻辑相似,但每次都要重… · 2026/9/27 22:48:38

基于ROS与Gazebo的AGV工业运输系统仿真实践
基于ROS与Gazebo的AGV工业运输系统仿真实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 23:30:07

硅碳相变:大模型API选型技术剖析,模型多为何项目更慢
硅碳相变:大模型API选型技术剖析,模型多为何项目更慢

硅碳相变:大模型API选型技术剖析,模型多为何项目更慢 如果你是一位后端工程师或AI应用开发者,大概率在某个深夜对着十几家AI API聚合平台的文档页反复切换过标签。每家都宣称自己接入了几百个模型,价格表长得像一份汇率牌价。真正… · 2026/9/27 23:30:07

Java面试被问Spring循环依赖,这样答加分
Java面试被问Spring循环依赖,这样答加分

三级缓存不是重点,AOP代理才是二级缓存就能解决普通对象的循环依赖:A实例化后放入二级缓存,B创建时能从二级缓存拿到A的早期引用。那为什么还要第三级?因为如果A需要被AOP代理,早期引用必须是代理对象,而不… · 2026/9/27 23:29:54

ab173 JSON懒人工具:零配置、离线、高安全的格式化校验神器
ab173 JSON懒人工具:零配置、离线、高安全的格式化校验神器

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 23:29:54

Windows 10下CH340驱动安装与文件替换实战指南
Windows 10下CH340驱动安装与文件替换实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 23:29:54

wordpress做微商城设计对比评测:备案不卡壳的5条黄金法则
wordpress做微商城设计对比评测:备案不卡壳的5条黄金法则

wordpress做微商城设计对比评测:备案不卡壳的5条黄金法则 很多老板一上来就问我:为什么我的wordpress做微商城,代码写得很漂亮,后台也配置好了,但就是没法正常访问?答案往往不在代码,而在 备案流程一头雾水 。… · 2026/9/27 23:29:54

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码