C ++ 20范围的切片视图

Mar*_*arc 4 c++ stl c++20

Python的itertoolsislice(seq, start, stop, step),需要一个序列,并返回每个的一个迭代过程step之间的序列值的个值startstop

C ++ 20的Ranges库是否提供类似的功能,例如slice,采用随机访问迭代器start,sentinel stop和step值的函数step,并返回对和step之间的每个th值进行迭代的随机访问迭代器?startstop

如果没有,可以使用Ranges库提供的原语来实现这种迭代器适配器。

(我知道如何手动实现这样的适配器,所以这不是问题。)

hon*_*onk 7

不幸的是,Range-v3slice和,如Barry'sanswer中所示,在C++20Ranges 库中(尚)不可用。但是,您可以通过组合和来替换。要替换,您可以使用范围适配器并向其传递特定的lambda 表达式。要像 Barry 的示例中那样过滤所有其他元素,我将使用带有init capture的有状态 lambda 表达式。您可以将所有内容放在一起来表示范围,如下所示:strideslicestd::views::drop_whilestd::views::take_whilestridestd::views::filter[10, 12, 14, 16, 18]

auto even_teens = std::views::iota(0, 100)
                | std::views::drop_while([](int i) { return i < 10; })
                | std::views::take_while([](int i) { return i < 20; })
                | std::views::filter([s = false](auto const&) mutable { return s = !s; });
Run Code Online (Sandbox Code Playgroud)

对于更通用的跨步解决方案,您可以在 lambda 表达式中使用计数器和模运算符。为了能够n以可读的方式指定步幅大小,我将使用以下 lambda 表达式,它提供了另一个跟踪步幅操作的 lambda 表达式:

auto stride = [](int n) {
    return [s = -1, n](auto const&) mutable { s = (s + 1) % n; return !s; };
};
Run Code Online (Sandbox Code Playgroud)

总而言之,最终的解决方案如下所示:

auto even_teens = std::views::iota(0, 100)
                | std::views::drop_while([](int i) { return i < 10; })
                | std::views::take_while([](int i) { return i < 20; })
                | std::views::filter(stride(2));
Run Code Online (Sandbox Code Playgroud)

Wandbox 上的代码


Bar*_*rry 6

不完全的。

C ++ 20将view::iota提供给您一个从起始值到前哨的序列。但是,它没有跨步功能。它只会增加(通过++)。

但是,您可以将其与range-v3 结合使用view::stride以添加步骤。那是:

auto evens = view::iota(0, 100) | view::stride(2); // [0, 2, 4, 6, ... ]
Run Code Online (Sandbox Code Playgroud)

对于现有范围,view::slice还没有大步前进。但是这些是正交的并且很好地分层:

auto even_teens  = view::iota(0, 100)
                 | view::slice(10, 20)
                 | view::stride(2); // [10, 12, 14, 16, 18]
Run Code Online (Sandbox Code Playgroud)