【问题标题】:Is it possible to use a dynamic number of range adaptors?是否可以使用动态数量的范围适配器?
【发布时间】:2022-01-10 07:58:03
【问题描述】:

我对范围相当陌生,我想知道是否有办法应用动态数量的范围适配器。折腾了一段时间的代码,也找了找,没用。

#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=')。似乎范围适配器的每个应用程序都需要一个新类型,因此我们无法动态创建此范围。有没有办法解决这个问题?

【问题讨论】:

  • 只...过滤实际容器真的更有意义。当您可以根据需要应用每个过滤器时,为什么还要使用惰性视图?

标签: c++ c++20 std-ranges


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    其中一种选择是将每次过滤的结果存储在一个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";
    }
    

    Demo.

    但是,这效率低下,也不是使用范围适配器的好用例。因此,您可能需要使用更高效的算法来实现这一点。

    【讨论】:

      【解决方案3】:

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

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

      可以并不意味着应该。这是非常低效的,因为它会为谓词创建一系列间接调用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-11-15
        • 2018-01-18
        • 1970-01-01
        • 2011-10-28
        • 2020-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多