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]反向代理grpc
前言 nginx从1.13.10版本开始提供对gRPC代理的支持.由于grpc基于http2,因此编译nginx时需要添加参数--with-http_v2_module来启用对http2协议的支持. ...
- Json 基于类 Newtonsoft.Json.Linq.JToken 的应用简介【C# 基础】
〇.前言 在日常开发中,对于 Json 的使用还是比较频繁的,特别是 Json 对象和字符串或者实体对象之间的转换. 虽然几乎天天用,但是总是感觉没那么明了,今天结合微软的 Newtonsoft.Js ...
- k8s实战案例之运行WordPress
1.WordPress架构 LNMP案例之基于Nginx+PHP实现WordPress博客站点,要求Nginx+PHP运⾏在同⼀个Pod的不同容器;nginx主要作用是接入站点请求,如果请求静态资源n ...
- 在.NET Framework中使用RocketMQ(阿里云版)实战【第二章】
章节 第一章:https://www.cnblogs.com/kimiliucn/p/17662052.html 第二章:https://www.cnblogs.com/kimiliucn/p/176 ...
- 分拣平台API安全治理实战 | 京东物流技术团队
导读 本文主要基于京东物流的分拣业务平台在生产环境遇到的一些安全类问题,进行定位并采取合适的解决方案进行安全治理,引出对行业内不同业务领域.不同类型系统的安全治理方案的探究,最后笔者也基于自己在金融领 ...
- nvm、node、vue安装、vue项目创建打包
nvm.node.vue安装.创建vue项目 nvm作用:可以管理多个版本的node,切换node版本,下载node. 前情提要 参 考:https://zhuanlan.zhihu.com/p/51 ...
- CopyOnWriteArrayList 写时复制思想
写时复制 conpyOnWrite容器即写时复制容器.往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是先将当前容器Object[]进行Copy,复制出一个新的容器Object[] ...
- 蓝桥杯真题——第十三届蓝桥杯大赛软件赛省赛 Python 大学 B 组
- CF1575I Illusions of the Desert
prologue 还是太菜了,这个 154 行的树剖 20min 才敲完. analysis 首先,处理这个给到我们的这个式子. \[\max(| a _ u + a _ v |, | a _ u - ...
- jmeter不用工具获取随机值的几种方法
第一种:直接获取 "vcContent": "${__time(yyyyMMddHHmmss)}${__RandomString(8,QWERTYUIOPASDFGHJK ...