【问题标题】:How to fill std::array with range from range-v3?如何用 range-v3 的范围填充 std::array?
【发布时间】:2019-07-12 13:34:25
【问题描述】:

我是 range-v3 库的完整初学者。假设我想在某个时间间隔内用随机数填充 std::array

对于迭代器,我会做类似this answer 的操作,将迭代器作为参数传递给我的std::array

template< class Iter >
void fill_with_random_int_values( Iter start, Iter end, int min, int max)
{
    static std::random_device rd;    // you only need to initialize it once
    static std::mt19937 mte(rd());   // this is a relative big object to create

    std::uniform_int_distribution<int> dist(min, max);

    std::generate(start, end, [&] () { return dist(mte); });
}

对于范围库,我想使用ranges::view::generate_n,它带有一个一元函数,可以生成一个随机数以及我的数组的大小。

auto random_num() -> int {
  static std::mt19937 engine{std::random_device{}()};
  static std::uniform_int_distribution<int> dist(1, 10);
  return dist(engine);
}

std::vector<int> nums = ranges::view::generate_n(random_num, 10);

这对std::vector 很有效,但我对应该使用什么算法来填充std::array 而不是生成std::vector 感到迷茫,因为与上述类似的方法不起作用。我可以transform 数组并忽略每个参数,但这似乎不对。

【问题讨论】:

标签: c++ c++20 range-v3


【解决方案1】:

std::array 是一个聚合;它没有用户提供的构造函数。因此,它没有从范围创建对象的构造函数。

您也不能(在 C++17 中)编写一个接受范围并返回数组的函数。原因是参数不是constexpr,数组的大小必须是常量表达式。 C++20 看起来正在增加将更多类型作为非类型模板参数的能力,因此应该可以将其作为模板参数。代码如下所示:

template<auto rng>
    requires std::ranges::sized_range<decltype(rng)>
constexpr auto array_from_range()
{
  std::array<std::iter_value_t<decltype(rng)>, std::ranges::size(rng)> ret;
  std::ranges::copy(rng, ret);
  return ret;
}

当然,这要求范围本身是constexpr,而不仅仅是它的大小。

【讨论】:

    【解决方案2】:

    std::array 的大小是一个编译时常量,所以我看不出库如何使用运行时参数为您生成一个。

    这是一个相当简单的实现,我认为它可以满足您的需求:

    #include <random>
    #include <array>
    #include <utility>
    #include <iostream>
    
    auto random_num() -> int {
      static std::mt19937 engine{std::random_device{}()};
      static std::uniform_int_distribution<int> dist(1, 10);
      return dist(engine);
    }
    
    template<class F, std::size_t...Is>
    auto generate_array_impl(F&& f, std::index_sequence<Is...>) -> std::array<decltype(f()), sizeof...(Is)>
    {
        return std::array<decltype(f()), sizeof...(Is)>
        {{
            (void(Is), f())...
        }};
    }
    
    template<std::size_t N, class F>
    auto generate_array(F f) -> std::array<decltype(f()), N>
    {
        return generate_array_impl(f, std::make_index_sequence<N>());
    }
    
    
    int main()
    {
        auto arr = generate_array<10>(random_num);
        for (auto x : arr)
        std::cout << x << '\n';
    }
    

    https://coliru.stacked-crooked.com/a/983064b89c4dd355

    或者添加一些 constexpr 魔法...

    #include <random>
    #include <array>
    #include <utility>
    #include <iostream>
    #include <boost/range.hpp>
    
    template<std::size_t N>
    constexpr auto c_size_t = std::integral_constant<std::size_t, N>();
    
    auto random_num() -> int {
      static std::mt19937 engine{std::random_device{}()};
      static std::uniform_int_distribution<int> dist(1, 10);
      return dist(engine);
    }
    
    template<class F, std::size_t...Is>
    constexpr auto generate_array_impl(F&& f, std::index_sequence<Is...>) -> std::array<decltype(f()), sizeof...(Is)>
    {
        return std::array<decltype(f()), sizeof...(Is)>
        {{
            (void(Is), f())...
        }};
    }
    
    template<std::size_t N, class F>
    constexpr auto generate_array(F&& f, std::integral_constant<std::size_t, N>) -> std::array<decltype(f()), N>
    {
        return generate_array_impl(f, std::make_index_sequence<N>());
    }
    
    int main()
    {
        auto arr = generate_array(random_num, c_size_t<10>);
        for (auto x : arr)
            std::cout << x << ',';
        std::cout << '\n';
    
        constexpr auto arr2 = generate_array([i = std::size_t(0)]() mutable { return i++; }, c_size_t<10>);
        for (auto x : arr2)
            std::cout << x << ',';
        std::cout << '\n';
    }
    

    https://coliru.stacked-crooked.com/a/42c9c011026779eb

    【讨论】:

      【解决方案3】:

      由于数组的大小是编译时常量。您必须自己构建它。你可以填写然后像

      std::array<int, 10> arr;
      ranges::generate(arr, random_num);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多