【发布时间】:2021-11-14 19:12:53
【问题描述】:
views::filter 异常行为的常见示例:
#include <iostream>
#include <ranges>
#include <vector>
int main ()
{
using namespace std;
auto ml = [](char c) // ml = make lambda (always accepts / transforms to 1)
{
return [c](int) {cout << c; return 1;};
};
vector<int> vec = {1};
auto view = vec
| views::transform (ml('T'))
| views::filter (ml('F'));
// use view somehow:
return *view.begin();
}
输出TFT(注意额外的T)。 demo
我们必须知道:
auto view = vec
| views::transform (ml('A'))
| views::filter (ml('B'));
...只是语法糖:
auto view = views::filter(views::transform(vec, ml('A')), ml('B'));
问题说明:
已经实现了views::filter 中的几个mock versions,问题似乎是:
- 与其他迭代器不同,
filter::iterator在operator ++期间工作(搜索可接受的值) -
operator *设计用于提取值,但使用filter::iterator,工作已经完成并丢失(我们不需要重新搜索可接受的值,但我们确实需要重新计算它) - 我们无法存储结果,因为视图的constant-time copy constraint(值可能是一个数组)
为了在图片中解释这一点,我们将表示迭代的过程:
view = container | Transform | Filter1 | Filter2 | Filter3
(为丑陋的图表道歉)圆圈代表Pr(F3) 正在为Print F3 完成的工作(模拟示例中完成的工作):
我们可以看到,如果我们只组合过滤器或只组合变换,那么我们就不会重复工作 - 问题在于变换上方有过滤器(在图表上方)。
在最坏的情况下,我们得到[n(x)x 的数量]:n(iterations) = n(filters) * n(transforms)
当我们期望n(filters) + n(transforms)
我们可以通过this example 看到这种抛物线与线性增长。
问题
有时需要先完成transforms,然后才能确定filter,那么如何避免额外的工作量?这似乎很重要,因为 views 旨在迭代容器,这是瓶颈领域。
有没有办法在这种情况下使用std::views 而不会出现上述巨大的减速?
【问题讨论】:
标签: c++ gcc g++ c++20 std-ranges