12

C++20 added std::to_array so you can easily create std::array from a C-Style array, for example:

template<typename T, std::size_t N>
void foo(const T (&a)[N]) {
    auto arr = std::to_array(a);
}

But, std::to_array does not support two-dimensional arrays, so the following will not work:

auto arr = to_array({1, 2}, {3, 4});

Can this be manually implemented?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Amir Kirsh
  • 12,564
  • 41
  • 74

1 Answers1

13

It can be implemented. And the following can work:

constexpr auto a = to_array({1, 2}, {4, 5, 6});
// ^ std::array<std::array<int, 3>, 2>
constexpr auto b = to_array("nice", "thing");
// ^ std::array<std::array<char, 6>, 2>

Here is the code:

template <typename T, std::size_t... N>
constexpr auto to_array(const T(&... arr)[N]) {
    constexpr size_t COLS = detail::max<N...>();
    return detail::to_2d_array_from_pack<sizeof...(N), COLS>(arr...);
}

With the following helpers:

namespace detail {

template <std::size_t N1, std::size_t... Ns>
constexpr size_t max() {
    if constexpr(sizeof...(Ns) == 0) return N1;
    else {
        constexpr size_t max_rest = max<Ns...>();
        return N1 > max_rest ? N1: max_rest;
    }
}

template <std::size_t TargetSize, typename T, std::size_t N, std::size_t... I>
constexpr auto to_array(std::index_sequence<I...>, const T (&arr)[N]) {
    return std::array<T, TargetSize>{arr[I]...};
}

template <std::size_t TargetSize, typename T, std::size_t N>
constexpr auto to_array(const T(&arr)[N]) {
    return to_array<TargetSize>(std::make_index_sequence<N>{}, arr);
}

template <std::size_t TargetRows, std::size_t TargetCols, typename T, std::size_t... N>
constexpr auto to_2d_array_from_pack(const T(&... arr)[N]) {
    using TargetType = std::remove_cv_t<T>;
    return std::array<std::array<TargetType, TargetCols>, TargetRows> {to_array<TargetCols>(arr)...};
}

} // end of namespace detail

Above supports only 2D arrays. To support 3D arrays we can add:

template <typename T, std::size_t... N, std::size_t... M>
constexpr auto to_array(const T(&... arr)[N][M]) {
    constexpr size_t Y_SIZE = detail::max<N...>();
    constexpr size_t Z_SIZE = detail::max<M...>();
    using TargetType = std::remove_cv_t<T>;
    return std::array<std::array<std::array<TargetType, Z_SIZE>, Y_SIZE>, sizeof...(N)> {
        detail::to_2d_array_from_array_of_arrays<Y_SIZE, Z_SIZE>(std::make_index_sequence<N>{}, arr)...
    };
}

With the following helper in namespace detail:

template <std::size_t TargetRows, std::size_t TargetCols, typename T,
  std::size_t N, std::size_t M, std::size_t... I>
constexpr auto to_2d_array_from_array_of_arrays(std::index_sequence<I...>, const T (&arr)[N][M]) {
    return to_2d_array_from_pack<TargetRows, TargetCols>(arr[I]...);
}
Amir Kirsh
  • 12,564
  • 41
  • 74