New Type Functions/Utilities for Dealing with Ranges in C++20
Generic Types of Ranges
类型萃取从字面意思上来说其实就是帮助我们挑选某个对象的类型,筛选特定的对象来做特定的事。可以先来回顾一下以前的写法。
#include <vector>
#include <iterator>
int main() {
std::vector v{1, 2, 3};
using iterator_type = std::vector<int>::iterator;
using difference_type = std::iterator_traits<iterator_type>::difference_type;
using iterator_catogory = std::iterator_traits<iterator_type>::iterator_category;
using pointer = std::iterator_traits<iterator_type>::pointer;
using reference = std::iterator_traits<iterator_type>::reference;
using value_type = std::iterator_traits<iterator_type>::value_type;
}
到了C++20,我们有了ranges,我们有了更多强大的工具,可以说它们是处理ranges的强大工具,我们来看看具体的内容。

通过上图,很多内容都直观明了,为了避免晦涩难懂的抽象话术,我们通过代码来看看具体用法。
#include <vector>
#include <ranges>
#include <algorithm>
#include <iterator>
#include <type_traits>
int main() {
std::vector v{10, 20, 30};
static_assert(std::is_same_v<std::ranges::iterator_t<decltype(v)>::difference_type,
std::iterator_traits<decltype(v)::iterator>::difference_type>); // OK
static_assert(std::is_same_v<std::ranges::iterator_t<decltype(v)>::pointer,
std::iterator_traits<decltype(v)::iterator>::pointer>); // OK
static_assert(std::is_same_v<std::ranges::iterator_t<decltype(v)>::reference,
std::iterator_traits<decltype(v)::iterator>::reference>); // OK
static_assert(std::is_same_v<std::ranges::iterator_t<decltype(v)>::value_type,
std::iterator_traits<decltype(v)::iterator>::value_type>); // OK
static_assert(std::is_same_v<std::ranges::iterator_t<decltype(v)>::iterator_category,
std::iterator_traits<decltype(v)::iterator>::iterator_category>); // OK
// 可以明显看到,比起传统的迭代器萃取,C++20的处理方式更加简洁,只用传入ranges类型,而不用传入迭代器类型,或许这就是ranges的魅力所在。
static_assert(std::is_same_v<std::ranges::sentinel_t<decltype(v)>,
decltype(end(v))>); // OK
// 获取哨兵类型。
static_assert(std::is_same_v<std::ranges::range_reference_t<decltype(v)>,
decltype(v[0])>); // OK, both are int&
static_assert(std::is_same_v<std::ranges::range_reference_t<decltype(v)>,
std::remove_reference_t<decltype(v[0])>>); // Error, int& and int
static_assert(std::is_same_v<std::ranges::range_value_t<decltype(v)>,
std::remove_reference_t<decltype(v[0])>>); // OK, both are int
static_assert(std::is_same_v<std::ranges::range_value_t<decltype(v)>,
decltype(v[0])>); // Error, int and int&
static_assert(std::is_same_v<std::ranges::range_size_t<decltype(v)>,
std::size_t>); // OK
static_assert(std::is_same_v<std::ranges::range_difference_t<decltype(v)>,
std::ptrdiff_t>); // OK
static_assert(std::is_same_v<std::ranges::range_rvalue_reference_t<decltype(v)>,
decltype(std::move(v[0]))>); // OK
static_assert(std::is_same_v<std::ranges::borrowed_iterator_t<decltype(v)>,
std::ranges::dangling>); // OK
static_assert(std::is_same_v<std::ranges::borrowed_subrange_t<decltype(v)>,
std::ranges::dangling>); // OK
}
Generic Types of Iterators
回到迭代器这一话题,为了更好的支持新的迭代器类型特征,你应该用如下的方式来代替传统的类型萃取。

#include <vector>
#include <ranges>
#include <type_traits>
#include <iterator>
int main() {
std::vector v{1, 2, 3};
using iterator_type = std::vector<int>::iterator;
static_assert(std::is_same_v<std::iter_value_t<std::ranges::iterator_t<decltype(v)>>, int>);
static_assert(std::is_same_v<std::iter_reference_t<std::ranges::iterator_t<decltype(v)>>, int&>);
static_assert(std::is_same_v<std::iter_rvalue_reference_t<std::ranges::iterator_t<decltype(v)>>, int&&>);
static_assert(std::is_same_v<std::iter_difference_t<std::ranges::iterator_t<decltype(v)>>, std::ptrdiff_t>);
using type1 = std::common_reference_t<int, int>; // int
using type2 = std::common_reference_t<int&, int>; // int
using type3 = std::common_reference_t<int&, int&>; // int&
using type4 = std::common_reference_t<int&, int&&>; // const int&
using type5 = std::common_reference_t<int&&, int&&>; // int&&
}
common_reference_t过于复杂,暂且先跳过。可以看到,这也是萃取类型的一种方式,只不过写法不同罢了。话说回来,std::ranges::range_value_t<Rg>其实就是std::iter_value_t<std::ranges::iterator_t<Rg>>的简化。
New Functional Types

std::identity是一个函数对象,返回对象本身,可以搭配ranges的算法一起使用。
#include <iostream>
#include <functional>
#include <vector>
#include <ranges>
#include <algorithm>
int main() {
std::vector v{1, 2, 3};
auto pos = std::ranges::find(v, 9, [](auto x) { return x * x; });
if (pos != end(v))
std::cout << "Exist\n";
auto pos2 = std::ranges::find(v, 3, std::identity{});
if (pos2 != end(v))
std::cout << "Exist\n";
auto pos3 = std::ranges::find(v, 3);
if (pos3 != end(v))
std::cout << "Exist\n";
}
pos处传入一个lambda表达式,对容器当中的每一个元素进行平方,然后返回对应的迭代器。pos2处传入的正是std::identity,即对象自身,相当于不对原容器进行任何的具体操作,它跟pos3本质上是相同的。
std::compare_three_way也是一个函数对象,它与<=>这个运算符有关联。这个运算符有个有意思的名字,叫宇宙飞船运算符,因为它的形状长得像宇宙飞船。这是C++20比较有意思的一个特性。
#include <iostream>
#include <type_traits>
#include <functional>
int main() {
int a{3}, b{4};
auto result = (a <=> b);
if (result < 0)
std::cout << "a < b\n";
else if (result == 0)
std::cout << "a == b\n";
else
std::cout << "a > b\n";
}
Other New Types for Dealing with Iterators

C++20,还有更多的值得探索......
New Type Functions/Utilities for Dealing with Ranges in C++20的更多相关文章
- 利用Azure Functions和k8s构建Serverless计算平台
题记:昨晚在一个技术社区直播分享了"利用Azure Functions和k8s构建Serverless计算平台"这一话题.整个分享分为4个部分:Serverless概念的介绍.Az ...
- Oracle PL/SQL中如何使用%TYPE和%ROWTYPE
1. 使用%TYPE 在许多情况下,PL/SQL变量可以用来存储在数据库表中的数据.在这种情况下,变量应该拥有与表列相同的类型.例如,students表的first_name列的类型为VARCHAR2 ...
- Oracle开发专题之:%TYPE 和 %ROWTYPE
1. 使用%TYPE 在许多情况下,PL/SQL变量可以用来存储在数据库表中的数据.在这种情况下,变量应该拥有与表列相同的类型.例如,students表的first_name列的类型为VARCHAR2 ...
- [转]Oracle开发专题之:%TYPE 和 %ROWTYPE
本文转自:http://www.cnblogs.com/kingjiong/archive/2009/02/19/1393837.html 1. 使用%TYPE 在许多情况下,PL/SQL变量可以用来 ...
- Oracle :%TYPE 和 %ROWTYPE
1. 使用%TYPE 在许多情况下,PL/SQL变量可以用来存储在数据库表中的数据.在这种情况下,变量应该拥有与表列相同的类型.例如,students表的first_name列的类型为VARCHAR2 ...
- 转载:oracle 自定义类型 type / create type
标签:type create oracle object record 一:Oracle中的类型有很多种,主要可以分为以下几类: 1.字符串类型.如:char.nchar.varchar2.nvarc ...
- oracle type类型
转载 http://blog.sina.com.cn/s/blog_6cfb6b090100ve92.html 转自网络,具体用法我会再细化 1.概念 方法:是在对象类型说明中用关键字 MEM ...
- oracle 自定义类型 type / create type
一:Oracle中的类型有很多种,主要可以分为以下几类: 1.字符串类型.如:char.nchar.varchar2.nvarchar2. 2.数值类型.如:int.number(p,s).integ ...
- net programming guid
Beej's Guide to Network Programming Using Internet Sockets Brian "Beej Jorgensen" Hallbeej ...
- Spring框架文档与API(4.3.6版本)
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/ Table of Contents I ...
随机推荐
- 优化nginx参数(基本通用参数)
全局域配置参数 worker_processes auto; worker_cpu_affinity auto; worker_rlimit_nofile 65530; 前两个参数用于开启nginx多 ...
- Win10安装Oracle-21C
1.前期工作 下载安装包:OracleXE213_Win64.zip 解压安装包 2.开始安装 注意:以管理员身份运行 ++++++++++++++++++++++分割线+++++++++++++++ ...
- java与es8实战之二:实战前的准备工作
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<java与es8实战>系 ...
- 【问题解决】容器部署MySQL的数据在docker commit导出的镜像中丢失
问题起因 最近公司有个甲方项目参加竞赛,要求在(基于kubeflow/arena)平台上部置应用,可以将MySQL打包在应用一起,也可以分开部署,没有提供volume相关的支持.大意是可以把初始好的数 ...
- Adapter 适配器模式简介与 C# 示例【结构型1】【设计模式来了_6】
〇.简介 1.什么是适配器模式? 一句话解释: 两个无关联的类,通过实现同一接口或继承对方得到新的适配器类,新的适配器类中通过实现原本类的操作,可达到进行相同的操作的目的. 适配器模式(Apapt ...
- Linux 内核设备驱动程序的IO寄存器访问 (下)
Linux 内核设备驱动程序通过 devm_regmap_init_mmio() 等函数获得 struct regmap 结构对象,该对象包含可用于访问设备寄存器的全部信息,包括定义访问操作如何执行的 ...
- Mysql基础9-事务
一.事务简介 事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有操作作为一个整体一起向系统提交或者撤销操作请求,即这些操作要么同时成功,要么同时失败.mysql的事务默认是自动提交的,也就 ...
- 《Python魔法大冒险》008 石像怪的挑战:运算符之旅
小鱼和魔法师继续深入魔法森林.不久,他们来到了一个巨大的魔法石圈旁边.石圈中心有一个闪闪发光的魔法水晶,周围则是一些神秘的符号.但令人意外的是,水晶的旁边还有一个巨大的石像怪,它的眼睛散发着红色的光芒 ...
- 关于oop的一点回忆
昨天在一个程序员行业群里看到别人发了一条消息, 大意是:要做好封装啦,不要随便用public啦,不要随便改别人代码啦. 说的好像就是我,因为,我这辈子最后悔的一件事情之一就是手贱改动别人代码. 那大概 ...
- java_方法使用细节
java_方法使用细节 1.一个方法想要返回多个值 思考?一个方法如何返回多个值 返回数组 class AA{ public int[] getSumAndSub(int n1, int n2){ / ...