当前位置: 首页 > article >正文

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

条款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.kler.cn/a/472498.html

相关文章:

  • 创建Java项目,并添加MyBatis包和驱动包
  • 用户界面的UML建模11
  • Linux存储管理之核心秘密(The Core Secret of Linux Storage Management)
  • Solidity合约编写(五)
  • unity 播放 序列帧图片 动画
  • Unity-Mirror网络框架-从入门到精通 总目录
  • 【利用 Unity + Mirror 网络框架、Node.js 后端和 MySQL 数据库】
  • c#委托和事件
  • 30、论文阅读:基于小波的傅里叶信息交互与频率扩散调整的水下图像恢复
  • 大数据技术(九)—— HBase优化
  • 【QT-QTableView实现鼠标悬浮(hover)行高亮显示+并设置表格样式】
  • SpringBoot中的设计模
  • 03、Docker学习,理论知识,第三天--DockerFile
  • linuxCNC(六)配置LinuxCNC完成伺服控制
  • pytorch torch.arange函数介绍
  • 鸿蒙中调整应用内文字大小
  • android的显式隐式intent
  • Taro+react 开发第一节创建 带有redux状态管理的项目
  • 使用图像过滤器在 C# 中执行边缘检测、平滑、浮雕等
  • 【每日学点鸿蒙知识】自定义弹窗实现分享、Badge切换闪动等
  • sqlalchemy CreateIndex
  • 第一次使用Git上传本地项目到github上
  • 探索Rancher服务发现机制:容器世界的“导航仪”
  • Spring AI ectorStore
  • 刚体变换矩阵的逆
  • Godot最佳实践个人转述