2

I would like to have this code with std::vector replaced with std::array, but I presume it can not be done since std::array is not a container std::ranges::to understands.

constexpr auto dice = std::views::iota(1, 7);
static_assert(dice.size() == 6);
std::print("{}\n", dice | std::ranges::to<std::vector>());

I know I can explicitly construct std::array, but I would like symmetry with std::vector usecase, and this seems quite repetitive and ugly since size and type of range are known at compile time:

constexpr auto arr = [&]() {
    std::array<std::ranges::range_value_t<decltype(dice)>, dice.size()> result;
    std::ranges::copy(dice, result.begin());
    return result;
}();
std::print("{}\n", arr);

I have also considered making some helper, like

struct to_arr_functor {
    template <std::ranges::range R>
    consteval auto operator()(const R& range) const {
        using T = std::ranges::range_value_t<R>;
        constexpr std::size_t N = std::ranges::size(range);
        std::array<T, N> arr{};
        std::ranges::copy(range, arr.begin());
        return arr;
    }

    template <std::ranges::range R>
    friend constexpr auto operator|(const R& range, const to_arr_functor& ta) {
        return ta(range);
    }
};

but the issue of no constexpr argument being possible prevents this from working.

P.S. I know in general views do not have size that is known without evaluating them(e.g. filter), but this question applies to all views that do have it, e.g. transform.

EDIT: one way I found to work is this, but it is not super pretty since I am reinventing the wheel(ranges::to)

template<auto& rng>
consteval auto to_arr() -> std::array<std::ranges::range_value_t<decltype(rng)>, std::ranges::size(rng)> {
    std::array<std::ranges::range_value_t<decltype(rng)>, rng.size()> result;
    std::ranges::copy(rng, result.begin());
    return result;
}
9
  • Duplicate of stackoverflow.com/q/54759619/4358570 maybe? Commented Mar 25 at 22:10
  • @IntelligentShadeofBlue partially, idk what smarter people will think... it does not mention ranges::to, but quite similar Commented Mar 25 at 22:24
  • actually I found a way to do it, not sure if it is legit way, will edit question. Commented Mar 25 at 22:38
  • 1
    No prob. It's just the 2nd time this week I saw someone use it and I got all FOMO'd ;) Commented Mar 26 at 3:10
  • 1
    dice | std::ranges::to<std::array> cannot possibly work because its static type depends on the value of dice. It has to be in the form my_ranges_to<dice, std::array> and therefore cannot really reuse std::ranges::to. I don't see much issue with your implementation. Commented Mar 26 at 3:30

1 Answer 1

2

But why even using <ranges>/Range-v3, here?

If you know the size of the array at compile time, then it needs not be a dynamic array, but a std::array is ok, and that's what you already know, as you asking about it, but my point is that you don't gain much from ranges' laziness here and you could just as well use an eager approach.

Furthermore, if you truly also know the elements, then why not leveraging integer_sequence?

#include <array>
#include <utility>

template<int ...i>
constexpr auto toArray(std::integer_sequence<int, i...>) {
    return std::array{i...};
}

static_assert(std::array{0,1,2,3} == toArray(std::make_integer_sequence<int, 4>{}));

You can do much more complex stuff too.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.