现在C++20ranges实现实际上已经在这里并且在GCC10.2下发布了,我想知道如何将ranges视图转换回一个实际的容器,比如一个向量。 我发现了这个问题(从视图到std::vector),它对预发布版本提出了同样的要求,但是我想知道,自从它发布以来,是否有任何新的方法将视图转换为容器? 还是那个问题的单一答案仍然是最好的解决方案?
最简单的方法就是使用range-v3,它有一个转换运算符。 从示例中可以看出:
using namespace ranges;
auto vi =
views::for_each(views::ints(1, 10), [](int i) {
return yield_from(views::repeat_n(i, i));
})
| to<std::vector>();
// vi == {1,2,2,3,3,3,4,4,4,4,5,5,5,5,5,...}
否则,链接问题中的答案并不完全准确,因为一个范围可能不具有相同的迭代器和哨兵类型,而答案需要相同的迭代器和哨兵类型。 所以我们可以做得更好一点:
template <std::ranges::range R>
auto to_vector(R&& r) {
std::vector<std::ranges::range_value_t<R>> v;
// if we can get a size, reserve that much
if constexpr (requires { std::ranges::size(r); }) {
v.reserve(std::ranges::size(r));
}
// push all the elements
for (auto&& e : r) {
v.push_back(static_cast<decltype(e)&&>(e));
}
return v;
}
上面的一个较短版本不一定预先保留所有相同的位置,它通过使用views::common
:
template <std::ranges::range R>
auto to_vector(R&& r) {
auto r_common = r | std::views::common;
return std::vector(r_common.begin(), r_common.end());
}
这里缺少保留的典型例子是使用std::list
调用to_vector()
,它有一个O(1)size()
可用,可用于保留,但一旦进入迭代器,就会丢失这个值。