Как заполнить std :: array диапазоном от range-v3? - PullRequest
0 голосов
/ 19 февраля 2019

Я начинающий с библиотекой 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 массив и игнорировать каждый аргумент, но это не так.

Ответы [ 3 ]

0 голосов
/ 19 февраля 2019

std::array - совокупность;у него нет пользовательских конструкторов.Таким образом, он не имеет конструкторов, которые создают объект из диапазона.

Вы также не можете (в C ++ 17) написать функцию, которая принимает диапазон и возвращает массив.Причина в том, что параметры не constexpr, а размер массива должен быть константным выражением.C ++ 20, похоже, добавляет возможность принимать больше типов в качестве нетиповых параметров шаблона, поэтому должна быть возможность сделать это в качестве параметра шаблона.Код будет выглядеть так:

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

Конечно, для этого требуется, чтобы сам диапазон был constexpr, а не только его размер.

0 голосов
/ 14 марта 2019

Поскольку размер массива является константой времени компиляции.Вы должны построить это самостоятельно.Вы можете заполнить его тогда как

std::array<int, 10> arr;
ranges::generate(arr, random_num);
0 голосов
/ 19 февраля 2019

Размер 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 / а / 42c9c011026779eb

...