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 ...
随机推荐
- 独奏者2 序章的wp
0x01 0ctf_2017_babyheap 2023.7.24 国防科技大学 合肥 本题除了fastbin attack,最重要的是伪造fakechunk,使得存放chunk的指针有两个指向同一个 ...
- next.js 源码解析 - getStaticProps、getStaticPaths 篇
好久前写了关于 getStaticProps 和 getStaticPaths 的内容,然而半年过去了源码解析就一直忘记了,不久前有人提醒才想起来,补下坑. 本文主要是解读下 getStaticPro ...
- Java 设计模式实战系列—单例模式
本文首发公众号:小码A梦 单例模式是设计模式中最简单一个设计模式,该模式属于创建型模式,它提供了一种创建实例的最佳方式. 单例模式的定义也比较简单:一个类只能允许创建一个对象或者实例,那么这个类就是单 ...
- 超全技术学习资料PDF分享
技术学习资料分享,目前共20G,持续更新... Java学习资料: 大数据Hadoop: 这里不一一截图了,资源持续更新中. 关注下面公众号进行下载.
- B2C在线教育商城--前后端分离部署
博客地址:https://www.cnblogs.com/zylyehuo/ 技术栈:vue + nginx + uwsgi + django + mariadb + redis 基本流程 vue打包 ...
- 循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(2)
在前面随笔<循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(1)>中介绍了Mvvm 的开发,以及一些界面效果,本篇随笔继续深入探讨 ...
- k8s 自动扩缩容HPA原理及adapter配置详解👑
大家好,我是蓝胖子,都知道,k8s拥有自动扩缩容机制HPA,我们能够通过配置针对不同的扩缩容场景进行自动扩缩容,往往初学者在面对其中繁多配置的时候会学了又忘记,今天我将会以一种不同的视角,结合api ...
- 日常Bug排查-读从库没有原子性?
日常Bug排查系列都是一些简单Bug排查.问题虽小,但经常遇到,了解这些问题,会让我们少走点弯路,提升效率.说不定有些问题你遇到过哦:) Bug现场 业务开发同学突然问了笔者一个问题,从库读会不会没有 ...
- Go 常用命令介绍
Go 常用命令 目录 Go 常用命令 一.Go 常用命令 1.1 go build 1.1.1 指定输出目录 1.1.2 常用环境变量设置编译操作系统和 CPU 架构 1.1.3 查看支持的操作系统和 ...
- 编译python为可执行文件遇到的问题:使用python-oracledb连接oracle数据库时出现错误:DPY-3010
错误原文: DPY-3010: connections to this database server version are not supported by python-oracledb in ...