最简单的做法是使用 range-v3,它有一个专门用于此目的的转换运算符。来自the examples:
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<T> 调用 to_vector() - 它有一个 O(1) size() 可用,可用于保留,但一旦我们进入迭代器。