垂直管道|在c++20和范围上下文中是什么意思?



|的一些用法看起来更像是函数管道连接或链接,而不是按位或,与c++20范围结合使用。比如:

#include <views>
#include <vector>
template<typename T>
std::vector<T> square_vector(const std::vector<T> &some_vector) {
auto result = some_vector | std::views::transform([](T x){ return x*x; };
return {result.begin(), result.end()};
}

,其中|运算符显然不是位或。从什么时候起,它工作,什么类型的函数/对象?这些是普通视图吗?有什么需要注意的?

这种函数链已经在c++ 20 range中引入,其最大的特性是允许对视图(更准确地说,是可视范围)上的操作进行延迟求值。这意味着转换视图的操作只会在它被迭代时作用于它。

这个语义允许管道语法糖,以一种可读的方式放置结果迭代时将发生的事情。与此一起使用的函数基于范围适配器,它接受一个视图(可能还有后面的附加参数),并在迭代时对其进行转换(本质上是返回另一个视图)。

管道语法是为其中一个特殊的子组保留的,叫做范围适配器闭包,它只接受一个视图,没有额外的参数。这些适配器可以是没有附加参数的适配器,绑定了多余参数的适配器,或者是一些库函数(如op中的std::views::transform)的结果。由于cpp23,您也可以自己定义这些。一旦我们有了其中的一些,语法:

some_viewable_range | std::views::some_adaptor_closure | some_other_adaptor_closure

等价于

some_other_adaptor_closure(std::views::some_adaptor_closure(some_viewable_range))

,它将在返回的视图迭代时计算管道。类似地,

some_vector | std::views::transform([](T x){ return x*x; });

相同
std::views::transform([](T x){ return x*x; })(some_vector); // The first call returns the adaptor std::views::transform(some_vector, [](T x){ return x*x; }) with the second argument bound.

,但更可读。

像任何视图一样,你可以直接迭代它们。因为这是懒惰的,所以可能会发生如下糟糕的事情:

template<typename T>
auto square_vector(const std::vector<T> &some_vector) {
return some_vector | std::views::transform([](T x){ return x*x; });
}
int main () {
for(auto val : square_vector(std::vector<int>{1, 2 ,3, 4, 5}))
std::cout << val << 'n';
}

当您打印val时,原始向量不存在,因此链的输入消失了,它从那里开始走下坡路。

要深入研究范围和适配器的世界,您可以查看https://en.cppreference.com/w/cpp/ranges,以及它们基于的原始库https://ericniebler.github.io/range-v3/。

相关内容

最新更新