I am fairly new to ranges, and I wanted to know if there was a way to apply a dynamic number of range adaptors. I have fiddled around with some code for a while, and I have also done some searching, but to no avail.
#include <iostream>
#include <ranges>
int main() {
auto output = std::ranges::views::iota(2, 100);
for (int i = 2; i < 100; i ) {
output = output | std::ranges::views::filter([i](int num){ return num % i != 0 || num == i; });
}
std::cout << "The 10th prime is: " << output[9] << "\n";
}
Essentially, I want something like this, but this gives a compile error (no match for 'operator='
). It seems that each application of a range adaptor requires a new type, so we can't dynamically create this range. Is there some way around this?
CodePudding user response:
For a fixed number like this, it would be possible to use metaprogramming to recursively build the range. You can do a truly dynamic number by type-erasing the ranges, such that the chain of filters is connected by virtual function calls. The result is slow and the code is painful, but it’s certainly possible.
CodePudding user response:
One of the alternatives is to store the results of each filtering in a vector
, which ensures that the range type after each operation is consistent and can be re-assigned.
#include <iostream>
#include <ranges>
#include <vector>
auto to_vector(std::ranges::view auto view) {
return std::vector(view.begin(), view.end());
}
int main() {
auto output = to_vector(std::views::iota(2, 100));
for (int i = 2; i < 100; i ) {
output = to_vector(output | std::views::filter(
[i](int num){ return num % i != 0 || num == i; }));
}
std::cout << "The 10th prime is: " << output[9] << "\n";
}
However, this is inefficient and not a good use case for using range adaptors. So you may need to use more efficient algorithms to implement this.