[英]c++20 ranges view to vector
現在 C++20 范圍實現實際上在這里並在 GCC 10.2 下發布,我想知道如何將范圍視圖轉換回實際容器,如矢量。 我發現這個問題( Range view to 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<T>
調用to_vector()
- 它有一個 O(1) size()
可用,可用於保留,但一旦我們將 go 放入迭代器。
使用Barry的答案並創建一個適配器:
/**
* \brief Creates a to_vector_closure for operator()
*/
struct to_vector_adapter
{
struct closure
{
/**
* \brief Gets a vector of a given range.
* \tparam R type of range that gets converted to a vector.
* \param r range that gets converted to a vector.
* \return vector from the given range.
*/
template<std::ranges::range R>
constexpr auto operator()(R&& r) const
{
auto r_common = r | std::views::common;
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));
}
v.insert(v.begin(), r_common.begin(), r_common.end());
return v;
}
};
/**
* \brief Gets a closure to convert the range to a vector.
* \return A to_vector_closure that will convert the range to a vector.
*/
constexpr auto operator()() const -> closure
{
return closure{};
}
template<std::ranges::range R>
constexpr auto operator()(R&& r)
{
return closure{}(r);
}
};
inline to_vector_adapter to_vector;
/**
* \brief A range pipe that results in a vector.
* \tparam R type of range that gets converted to a vector.
* \param r range that gets converted to a vector.
* \param a used to create the vector.
* \return a vector from the given range.
*/
template<std::ranges::range R>
constexpr auto operator|(R&& r, aplasp::planning::to_vector_adapter::closure const& a)
{
return a(std::forward<R>(r));
}
有了這個你可以做類似的事情(其中numbers
是int
的范圍):
std::vector foo
{
numbers
| std::views::filter([](int n){ return n % 2 == 0; })
| std::views::transform([](int n){ return n * 2; })
| to_vector();
};
或者
std::vector foo
{
to_vector(
numbers
| std::views::filter([](int n){ return n % 2 == 0; })
| std::views::transform([](int n){ return n * 2; }))
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.