条款47:请使用 traits classes 表现类型信息(Use traits classes for information about types)

news/2025/1/8 14:16:44/

条款47:请使用 traits classes 表现类型信息

1.1 提出问题

想一想,下面的功能如何实现?(可以查看std::advance源码)

template<typename IterT, typename DistT>  
void advance(IterT& iter, DistT d); //前进iter d个单位;如果d<0,将iter向后移动 

迭代器有很多类型,所以实现并不是iter+=d这么简单,需要考虑不同的迭代器类型。

struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d)
{
//我们需要获取类型的信息,以选择最快的方式
//这就是traits的作用:它们允许你在编译期间获取有关类型的信息。if (iter 是随机访问迭代器) {iter += d;  }  else {if (d >= 0) { while (d--) ++iter; }  else { while (d++) --iter; }  } 
}

1.2 解决办法

trait不是C++中的关键字或预定义结构;它们是C++程序员遵循的一种技术和约定。对该技术的要求之一是,它必须像对自定义类型一样对待内置类型。意味着在类型中嵌套信息之类的无法实现,因为没有办法在指针内部嵌套信息。因此,类型的traits信息必须位于类型的外部。

template<typename IterT> 
struct iterator_traits; // 关于迭代器类型信息的模板//deque迭代器的类如下所示:
template < ... > // 模板参数被省略
class deque {
public:class iterator {public:     
//任何自定义的迭代器类型都必须包含一个嵌套的名为iterator_category的typedef,用于确认迭代器的分类。typedef random_access_iterator_tag iterator_category;...} :...
};

Iterator_traits只是鹦鹉学舌地响应了iterator类的嵌套typedef:

// IterT类型的iterator_category是IterT指定的类型
template<typename IterT>
struct iterator_traits {typedef typename IterT::iterator_category iterator_category;...
};
//这对于自定义类型很有效,但对于指针类型的迭代器根本不起作用,因为不存在具有嵌套typedef的指针。

iterator_traits为指针类型提供了模板的偏特化。指针充当随机访问迭代器,因此iterator_traits为它们指定了类别:

template<typename IterT> 	 
struct iterator_traits<IterT*> // 内置指针类型的模板偏特化
{typedef random_access_iterator_tag iterator_category;...
};

有了iterator_traits,(实际上它是标准库的一部分)我们可以改进advance的伪代码:

template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d)
{
//typeid运行时获知变量类型名称if (typeid(typename std::iterator_traits<IterT>::iterator_category) ==typeid(std::random_access_iterator_tag))...
}
//在 C++17 之后,可以使用if constexpr:
//if 语句将在运行时期进行判断

我们可以通过重载,在编译期进行判断:

template<typename IterT, typename DistT> // 用于随机访问迭代器
void doAdvance(IterT& iter, DistT d, std::random_access_iterator_tag)  
{iter += d;
}
template<typename IterT, typename DistT> // 用于双向迭代器
void doAdvance(IterT& iter, DistT d, std::bidirectional_iterator_tag) 
{if (d >= 0) { while (d--) ++iter; }else { while (d++) --iter; }
}
template<typename IterT, typename DistT> // 用于输入迭代器
void doAdvance(IterT& iter, DistT d, std::input_iterator_tag)
{if (d < 0) {throw std::out_of_range("Negative distance"); }while (d--) ++iter;
}
template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d)
{doAdvance(iter, d, typename std::iterator_traits<IterT>::iterator_category()); 
} 

1.3 总结

  1. traits类提供编译期间可用的类型信息。它们是使用模板和模板特化实现的。
  2. 与重载相结合,traits类可以在编译时执行“if……else”对类型进行测试。

http://www.ppmy.cn/news/1561256.html

相关文章

游戏引擎学习第74天

仓库: https://gitee.com/mrxiao_com/2d_game (仓库满了) gitee 好像一个仓库最多1G https://gitee.com/mrxiao_com/2d_game_2 后面改到https://gitee.com/mrxiao_com/2d_game_2 仓库 代码占的内存不大主要是markdown截图700多兆比较占内存 Blackboard: 以对处理实体对的方式进…

代码随想录 day62 第十一章 图论part11

第十一章&#xff1a;图论part11 Floyd 算法精讲 Floyd 算法代码很简单&#xff0c;但真正理解起原理 还是需要花点功夫&#xff0c;大家在看代码的时候&#xff0c;会发现 Floyd 的代码很简单&#xff0c;甚至看一眼就背下来了&#xff0c;但我为了讲清楚原理&#xff0c;本…

SQL 实现复杂地理围栏 – 多边形区域判断与距离筛选

在位置服务、物流配送、LBS&#xff08;基于位置的服务&#xff09;等场景中&#xff0c;地理围栏&#xff08;Geofence&#xff09;是一个重要功能。通过 SQL 查询&#xff0c;我们可以借助空间索引和地理函数&#xff0c;精准判断目标是否在多边形区域内&#xff0c;或计算两…

同步与并发:Java的同步舞蹈

现在&#xff0c;我们将深入探讨同步与并发&#xff0c;这是确保多线程程序正确性和效率的关键&#xff0c;就像是Java的同步舞蹈。 1 并发的概念 并发是指在多处理器系统中&#xff0c;多个操作或多个线程同时进行执行。在Java中&#xff0c;这意味着能够有效地利用多核处理…

IDE和IDEA详解和具体差异

1. IDE(集成开发环境)概述 1.1 什么是 IDE? IDE(Integrated Development Environment,集成开发环境)是一种为开发者提供全面编程工具的软件应用程序。它将代码编辑、编译、调试、版本控制等功能集成在一个统一的界面中,旨在提高开发效率,减少开发者在不同工具之间切换…

Deep blind super-resolution for hyperspectral images_译文

关键词&#xff1a; 高光谱图像 盲超分辨率 退化模型 深度学习 摘要 目前单张高光谱图像超分辨率的深度学习方法都是非盲方法&#xff0c;采用简单的双三次退化模型。这些模型泛化性能较差&#xff0c;无法处理未知的退化。此外&#xff0c;RGB图像的盲超分辨率方法忽略了高光…

HTML5 缩放动画(Zoom In/Out)详解

HTML5 缩放动画&#xff08;Zoom In/Out&#xff09;详解 缩放动画是一种常见的视觉效果&#xff0c;用于使网页元素逐渐放大或缩小&#xff0c;从而吸引用户的注意力。下面将介绍如何使用 CSS 和 JavaScript 实现这种动画效果。 1. 使用 CSS 实现缩放动画 可以通过 CSS 的 …

Vue3苦逼的学习之路

从一名测试转战到全栈是否可以自学做到&#xff0c;很多朋友肯定会说不可能&#xff0c;或就算转了也是个一般水平&#xff0c;我很认同&#xff0c;毕竟没有经过各种项目的摧残&#xff0c;但是还是得踏足一下这个领域。所以今天和大家分享vue3中的相关内容&#xff0c;大佬勿…