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;
}
dice | std::ranges::to<std::array>cannot possibly work because its static type depends on the value ofdice. It has to be in the formmy_ranges_to<dice, std::array>and therefore cannot really reusestd::ranges::to. I don't see much issue with your implementation.