The std::views::filter
can’t model the std::ranges::random_access_range
concept (most likely because it can’t map random access from temporary filtered range to original range; correct me if I am wrong in reasoning or wording).
I can use std::ranges::to<std::vector>()
(see demo below) to convert the temporary range to the vector, but:
- It creates a copy of the values in the vector
v
and I can’t change them. Is there a way to solve this? - Is it the best (most efficient from performance and memory reallocation perceptive) approach?
- What would be the real impact on performance and memory reallocation? Would the real std::vector be created dynamically in memory?
(Of course, “most efficient” means here “without the context”; for sure in real cases the code of rar
function could be changed to process filtering inside, avoiding extra allocations. The question is, can this be done better if rar
function is “untouchable”?)
#include <algorithm>
#include <ranges>
#include <vector>
#include <iostream>
constexpr auto rar = []<std::ranges::random_access_range Rng>(Rng & range) {
std::ranges::for_each(range, [](auto& v) { v = 0.0f; });
};
int main()
{
std::vector<float> v = { 0.0f, 1.0f, 0.0f, 2.0f };
// rar(v);
auto no_zeros = v | std::views::filter([](const auto& lhs) { return lhs != 0.0f; });
// This won't compile since std::views::filter can't produce std::ranges::random_access_range for the created range
// rar(no_zeros);
// Is this the only possible way and what is the performance/memory allocation impact?
auto no_zeros_as_vector = v | std::views::filter([](const auto& lhs) { return lhs != 0.0f; }) | std::ranges::to<std::vector>();
rar(no_zeros_as_vector);
std::ranges::copy
(
v,
std::ostream_iterator<float>{std::cout, ", "}
);
std::cout << std::endl;
}