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

条款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.lryc.cn/news/515116.html

相关文章:

  • yolov5和yolov8的区别
  • Redis 实现分布式锁
  • django StreamingHttpResponse fetchEventSource实现前后端流试返回数据并接收数据的完整详细过程
  • SpringSpringBoot常用注解总结
  • 24.小R的随机播放顺序<字节青训营-中等题>
  • 【QT】增删改查 XML 文件的类
  • Linux-掉电保护方案
  • php获取字符串中的汉字
  • java: JDK isn‘t specified for module ‘product-service‘问题解决
  • 使用工厂+策略模式实现去除繁琐的if else
  • Dubbo3入门项目搭建
  • 形象地理解UE4中的数据结构 TLinkedListBase
  • Python自然语言处理利器:SnowNLP模块深度解析、安装指南与实战案例
  • Llama系列关键知识总结
  • 【开源】创建自动签到系统—QD框架
  • ​​​​​​​CDP集群安全指南系列文章导读
  • MT8788安卓核心板_MTK8788核心板参数_联发科模块定制开发
  • 【微软,模型规模】模型参数规模泄露:理解大型语言模型的参数量级
  • 深入理解并发原子性、可见性、有序性与JMM内存模型
  • 电商项目-数据同步解决方案(四)商品下架同步更新ES索引库数据
  • vue学习第一阶段
  • React虚拟DOM:理解和应用
  • 用python编写一个放烟花的小程序
  • Git 仓库与文件管理笔记
  • 2024 年 docker 提示index.docker.io
  • TCP粘/拆包----自定义消息协议
  • Modbus知识详解
  • Java-创建一个结合CompletableFuture和自定义功能的工具类
  • 【MATLAB第111期】基于MATLAB的sobol全局敏感性分析方法二阶指数计算
  • C语言-sprintf