如何用 range-v3 的范围填充 std::array?
How to fill std::array with range from range-v3?
我是 range-v3 库的完全初学者。假设我想在某个区间内用随机数填充 std::array
。
使用迭代器,我会做类似 的事情,将迭代器作为参数传递给我的 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
数组并忽略每个参数,但这似乎不对。
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';
}
std::array
是聚合;它没有用户提供的构造函数。因此,它没有从范围创建对象的构造函数。
您也不能(在 C++17 中)编写接受范围和 returns 数组的函数。原因是参数不是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
,而不仅仅是它的大小。
因为数组的大小是一个编译时常量。你必须自己构建它。你可以填写它然后喜欢
std::array<int, 10> arr;
ranges::generate(arr, random_num);
我是 range-v3 库的完全初学者。假设我想在某个区间内用随机数填充 std::array
。
使用迭代器,我会做类似 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
数组并忽略每个参数,但这似乎不对。
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';
}
std::array
是聚合;它没有用户提供的构造函数。因此,它没有从范围创建对象的构造函数。
您也不能(在 C++17 中)编写接受范围和 returns 数组的函数。原因是参数不是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
,而不仅仅是它的大小。
因为数组的大小是一个编译时常量。你必须自己构建它。你可以填写它然后喜欢
std::array<int, 10> arr;
ranges::generate(arr, random_num);