fold,折叠,这个在前面分析c++17中的fold expression,这个也差不多。只过过在Ranges中,flod会变得更强大一些。但是说句实话,乍一接触这个的开发者,绝大多数可能都要懵圈。毕竟,它的使用方式和传统的理解上有着不同的处理方式。人们更适合的是正向的,反向的,或者分片处理,这都容易理解,但这个折叠,却有点不同。它是对一个单元(只要允许)进行递归处理来实现某种操作(或者说算法逻辑)。
c++23中,兼顾是左右两个方向的Fold,这对Ranges中的应用就非常友好了,fold算法的好处在于它可以忽略初始值的类型。比如初始值为int,那么如果计算的是double,原来的std::accumulate返回就是int。同时,这几个fold算法中,有的使用了std::optional,如果传入计算的单元是一个空值,就更加容易体现出来,也就是增强了安全性,而其它如Max等可能就会出现UB的行为。
当然左右的转换还可以自己实现,即使用views::reverse来进行操作,当然操作数也需要自己交换一下。
在c++STL中,如果使用过std::accumulate的开发者,基本就比较好理解加法的累加其实就是一种递归的形式。看一下它的实现:
// accmulate原型
template inline
_Ty _Accmulate(_Init _First, _Init _Last, _Ty _Val, _Fn2 _Func)
{
for (; _First != _Last; ++_First) {
// _Func为回调函数
_Val = _Func(_Val, * _First);
}
return _Val;
}
在c++23中提供了以下几种fold:
ranges::fold_right_last:left-folds a range of elements
ranges::fold_left:right-folds a range of elements
ranges::fold_left_first:right-folds a range of elements using the last element as an initial value
ranges::fold_left_with_iter:left-folds a range of elements, and returns a pair (iterator, value)
ranges::fold_left_first_with_iter:left-folds a range of elements using the first element as an initial value, and returns a pair (iterator, optional)
还有两个更早提供的,accumulate和reduce(c++17).这此通过上面的函数都可以知道它们的作用,看其中一个例程:
#include
#include
#include
#include
#include
#include
#include
using namespace std::literals;
int main()
{
auto v = {1, 2, 3, 4, 5, 6, 7, 8};
std::vector vs {"A", "B", "C", "D"};
auto r1 = std::ranges::fold_right(v.begin(), v.end(), 6, std::plus<>()); // (1)
std::cout << "r1: " << r1 << '\n';
auto r2 = std::ranges::fold_right(vs, "!"s, std::plus<>()); // (2)
std::cout << "r2: " << r2 << '\n';
// Use a program defined function object (lambda-expression):
std::string r3 = std::ranges::fold_right
(
v, "A", [](int x, std::string s) { return s + ':' + std::to_string(x); }
);
std::cout << "r3: " << r3 << '\n';
// Get the product of the std::pair::second of all pairs in the vector:
std::vector> data {{'A', 2.f}, {'B', 3.f}, {'C', 3.5f}};
float r4 = std::ranges::fold_right
(
data | std::ranges::views::values, 2.0f, std::multiplies<>()
);
std::cout << "r4: " << r4 << '\n';
}
运行结果:
r1: 42
r2: ABCD!
r3: A:8:7:6:5:4:3:2:1
r4: 42
更多可以参看:
https://zh.cppreference.com/w/cpp/algorithm/ranges/fold_right
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2322r6.html
总之,c++标准朝着简单易用功能强大在不断演进,这是不争的事实。但是这种演进最终会成为什么样子,还真得不好说。不过从今年看c++算是又焕发了生机,甩过了Java,直追C,希望能一直保持下去。ChagGpt并没有想象的那么强大,c++未来可期。