Объединить диапазон диапазонов в диапазон

Пусть rw = ranges::views.

Пытаюсь создать исключительно с помощью range-v3 аналог конструкции:

std::vector<int> v;

// range = {0, 1, 2}
auto range = rw::ints (0, 3);

for (int i : range)
    for (int j : range)
        v.push_back (func (i, j))

// v = {func (0, 0), func (0, 1), func (0, 2),
//      func (1, 0), func (1, 1), func (1, 2),
//      func (2, 0), func (2, 1), func (2, 2)}

Я попробовал следующий вариант:

// range = {0, 1, 2}
auto range = rw::ints (0, 3);

// range_of_ranges = {{func (0, 0), func (0, 1), func (0, 2)},
//                    {func (1, 0), func (1, 1), func (1, 2)},
//                    {func (2, 0), func (2, 1), func (2, 2)}}
auto range_of_ranges = rw::transform (range, [] (int i) {
    return rw::transform (range, [i] (int j) { return func (i, j); });
});

// result = {func (0, 0), func (0, 1), func (0, 2),
//           func (1, 0), func (1, 1), func (1, 2),
//           func (2, 0), func (2, 1), func (2, 2)}
auto result = rw::concat (range, range, range);

for (auto x : result)
    printf ("%d\n", x);

Но если я заменю

// result = {func (0, 0), func (0, 1), func (0, 2),
//           func (1, 0), func (1, 1), func (1, 2),
//           func (2, 0), func (2, 1), func (2, 2)}
auto result = rw::concat (range, range, range);

с

// result = { {{func (0, 0), func (0, 1), func (0, 2)},
//             {func (1, 0), func (1, 1), func (1, 2)},
//             {func (2, 0), func (2, 1), func (2, 2)}} }
auto result = rw::concat (range_of_ranges);

будет предупреждение компилятора:

warning: format specifies type 'int' but the argument has type 'ranges::iota_view<int, int>' [-Wformat]
    printf ("%d\n", x);

К сожалению, это не работает, и я не очень понимаю, как это исправить. Я понимаю, что функция concat должна принимать свои аргументы и объединять их в диапазон, и я только что создал диапазон длиной 1, но я не знаю, какое решение будет правильным. Не могли бы вы дать мне подсказку?

UPD[1] (на основе комментария Jarod42: range-v3 имеет views::cartesian_product): оказалось, упростите код до следующего:

auto range = rw::ints (0, 3);

auto cart_prod = rw::cartesian_product (range, range);

auto unpack_args_and_call_func = [] (const auto &arg) {
    return std::apply (func, arg);
};

auto result = rw::transform (cart_prod, unpack_args_and_call_func);

Однако использование аргумента распаковки выглядит не очень красиво и удобно.

UPD[2] (на основе комментария Jarod42: есть также views::join для вашего range_of_ranges): Заменять

// result = {func (0, 0), func (0, 1), func (0, 2),
//           func (1, 0), func (1, 1), func (1, 2),
//           func (2, 0), func (2, 1), func (2, 2)}
auto result = rw::concat (range, range, range);

с

// result = { {{func (0, 0), func (0, 1), func (0, 2)},
//             {func (1, 0), func (1, 1), func (1, 2)},
//             {func (2, 0), func (2, 1), func (2, 2)}} }
auto result = rw::join (range_of_ranges);

person Alexey Ismagilov    schedule 21.05.2021    source источник
comment
диапазон-v3 имеет views::cartesian_product   -  person Jarod42    schedule 21.05.2021
comment
Есть также views::join для вашего range_of_ranges.   -  person Jarod42    schedule 21.05.2021
comment
использование аргумента распаковки выглядит не очень красиво и удобно. основано на мнении... Я нахожу это более ясным, чем ваш черепичный transform.   -  person Jarod42    schedule 21.05.2021


Ответы (1)


Спасибо Jarod42.

// range = {0, 1, 2}
auto range = rw::ints (0, 3);

// range_of_ranges = {{func (0, 0), func (0, 1), func (0, 2)},
//                    {func (1, 0), func (1, 1), func (1, 2)},
//                    {func (2, 0), func (2, 1), func (2, 2)}}
auto range_of_ranges = rw::transform (range, [] (int i) {
    return rw::transform (range, [i] (int j) { return func (i, j); });
});

// result = {func (0, 0), func (0, 1), func (0, 2),
//           func (1, 0), func (1, 1), func (1, 2),
//           func (2, 0), func (2, 1), func (2, 2)}
auto result = rw::join (range_of_ranges);

for (auto x : result)
    printf ("%d\n", x);
person Alexey Ismagilov    schedule 21.05.2021