标准库range笔记
以前使用range-v3, C++21中增加了range的支持, 但是感觉差异还是蛮大的. 慢慢收集总结一下.
使用std::range
和range-v3
的差别
使用range-v3
,最简单的方式是#include <range/v3/all.hpp>
,把所有的头文件都放进去就是了。编译速度慢就慢了,大不了扔到预编译头文件里面去。
使用std::range
,好像标准库没有给出一个合集,所以需要自己一点点加进去。目前,ranges
和algorithm
是至少需要的。
range-v3和std::range的对比-views
大家都有的:
all
cartesian_product
chunk
,chunk_by
concat
counted
common
drop
,drop_while
empty
enumerate
filter
iota
,range-v3的ints
也比较接近keys
,values
join
repeat
reverse
single
split
stride
take
,take_while
transform
zip
to
—std::range有的
adjacent
,slide
:注意两者的区别。功能是一样的,但是返回值类型和参数不一样。跟range-v3的sliding
在功能上近似。lazy_split
elements
:这个很牛逼,在range-v3
里面没有找到类似的东西。zip_transform
adjacent_transform
join_with
—range-v3有的
zip_with
take_exactly
,take_last
,split_when
drop_last
,drop_exactly
addressof
adjacent_filter
,adjacent_remove_if
any_view<T>(rng)
c_str
cachel
const_
cycle
delimit
for_each
generate
,generate_n
indirect
intersperse
ints
linear_distribute
move
partial_sum
remove
,remove_if
repeat_n
replace
,replace_if
sample
sliding
tail
tokenize
trim
unbounded
unique
adaptor类和adaptor方法
在std::ranges
的手册中,Range adaptors,Range factories都是有两个的。比如,ranges::reverse_view
,views::reverse
。他们放在一起。
但是两个不是一个东西。ranges::reverse_view
是一个类,views::reverse
是一个方法。功能上一样,使用上有区别:
1 | std::vector<int> r = {1, 2, 3, 4, 5}; |
建议使用views::reverse
这种。
algorithnm和action的概念
在range-v3
中,有views
和actions
的概念。views是创建惰性视图,知道需要时才进行计算,而action直接处理存在的集合,并立即执行所需的操作。所以,range-v3
里面的action列表,很多项在views里面都有对应的同名项。
std::ranges::sort
的projection
std::ranges::sort
的接口形式和传统的std::sort
有一点不同,它除了表示range的参数外,还有一个comp
参数和一个proj
参数。其中,comp
是比较函数,而proj
是projection函数。proj
会对range的每个成员计算,将结果给comp
函数来做比较。
这个参数比较有意思,我们知道,传统的std::sort
也有comp
参数,它完成了这里的投影和计算两个功能,而在ranges库里面,把它分开了。为啥呢?或许是为了解耦比较运算?
comp
的默认值是{}
,此时使用ranges::less
,如果要修改,我们需要人工提供, 例如,ranges::greater()
。从cppreference里面的说法,std::ranges::less
必须实现所有六个比较运算符:<, <=, >, >=, == and !=
.
proj
的默认值是std::identity
,就是不改变的意思。
比如下面的代码:
1 | std::vector vec{ -1, 2, 5, 3, -6, 7, -12 }; |
这里我的困惑主要是在于,为什么要把projection和compare两个分开。背后的思想究竟是什么,是不是我猜测的解耦,还是有别的意图?