是否可以使用动态数量的范围适配器?

4

我对范围(ranges)比较陌生,想知道是否有一种方法可以应用动态数量的范围适配器。我已经尝试了一些代码,也进行了一些搜索,但没有找到合适的方法。

#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";
}

我想要的是这样的东西,但是这会导致编译错误(no match for 'operator=')。似乎每个范围适配器都需要一个新类型,因此我们无法动态创建此范围。有什么解决方法吗?


1
更有意义的做法是直接过滤实际容器。为什么要使用惰性视图,当你可以根据需要应用每个过滤器呢? - Nicol Bolas
3个回答

6
对于像这样的固定数字,可以使用元编程来递归地构建范围(尽管可能会达到模板实例化深度限制)。您可以通过类型擦除范围来做到真正的动态数字,使过滤器链通过虚函数调用连接。结果速度慢且代码难看,但肯定是可行的。

4

其中一种选择是将每次过滤的结果存储在一个vector中,这样可以确保每个操作后的范围类型是一致的,并且可以被重新分配。

#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";
}

演示链接。

然而,这种方法是低效的,并不适合使用范围适配器。因此,您可能需要使用更高效的算法来实现此操作。


1
在这种情况下,您可以构建过滤谓词:

int main() {
    auto output = std::views::iota(2, 100);

    std::function<bool(int)> filter_fn = [] (int) { return true; };

    for (int i = 2; i < 100; i++)
    {
        filter_fn = [=] (int num) {
            return filter_fn(num) && (num % i != 0 || num == i);
        };
    }

    auto primes = output | std::views::filter(filter_fn);

    std::cout << "The 10th prime is: " <<
        (primes | std::views::drop(9)).front() << "\n";
}

但是,可以并不意味着应该这样做。这种方法效率相对较低,因为它会为谓词创建一系列的间接调用链。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接