【发布时间】:2021-07-15 13:55:22
【问题描述】:
sized_range概念根据以下要求细化范围 范围内的元素数量可以在 amortized 中确定 恒定时间使用ranges::size。template<class T> concept sized_range = range<T> && requires(T& t) { ranges::size(t); };
标准规定获取ranges::sized_range 的大小保证在恒定时间内。考虑以下几点:
auto r1 = std::views::iota(0)
| std::views::filter([](int x){ return x % 2 == 0; })
| std::views::take(1'000'000);
r1 显然不是sized_range,因为不可能得到它的大小
常数时间,这也意味着我们使用ranges::size 来评估它的大小也是病态的。
但我偶然发现,如果我们在上面应用views::reverse,新的范围r2突然变成了sized_range,我们可以直接使用ranges::size来正确获取它的大小,godbolt:
auto r2 = r1 | views::reverse;
static_assert(!ranges::sized_range<decltype(r1)>);
static_assert( ranges::sized_range<decltype(r2)>);
std::cout << std::ranges::size(r2) << "\n"; // print 500'000
但是,很明显,新范围 r2 不是 sized_range,因为我们永远无法在恒定时间内获得它的大小,这似乎违反了标准的规定。
为什么views::reverse 可以将非sized_range 转换为sized_range?显然,这种转换不会对原始范围的大小产生任何影响。这是标准缺陷还是库错误?
【问题讨论】:
-
请注意,
r2.size()确实以candidate: 'constexpr auto std::ranges::reverse_view<_Vp>::size() requires sized_range<_Vp>失败。 -
“amortized”在这里做了很多工作。
标签: c++ c++20 range-v3 std-ranges