Я реализую контейнер в виде многомерного массива. Я пытаюсь воспроизвести std :: to_array (C ++ 20), функцию, которая создает std :: array из одномерного встроенного массива, ...

1
Savaria 9 Апр 2021 в 00:31

2 ответа

Лучший ответ

К сожалению, моя обычная тенденция использования однострочников Boost.Mp11 подходит к концу, поскольку Boost.Mp11 не очень хорошо работает с значениями , и нам нужно преобразовать int[5][12] в { {X1}} и нет простого механизма, чтобы сделать это с этой библиотекой.

Вместо этого мы просто делаем это вручную. std::extent дает вам N -ю степень и std::rank показывает количество экстентов. Объедините это с make_index_sequence, и вы получите их все:

template <typename T, typename>
struct mdarray_for_impl;

template <typename A, size_t... Is>
struct mdarray_for_impl<A, std::index_sequence<Is...>> {
    using type = mdarray<std::remove_all_extents_t<A>, std::extent_v<A, Is>...>;
};

template <typename T>
using mdarray_for = mdarray_for_impl<T, std::make_index_sequence<std::rank_v<T>>>::type;

Здесь mdarray_for<int[1][2][3]> даст тип mdarray<int, 1, 2, 3>.


В любом случае версия Boost.Mp11 требуется пара псевдонимов помощников

// a type-only mdarray
template <typename T, typename... Ns>
using mdarray_t = mdarray<T, Ns::value...>;

// a type-only extent
template <typename T, typename V>
using mp_extent = mp_size_t<std::extent_v<T, V::value>>;

Что затем позволяет:

template <typename T>
using mdarray_for2 = 
    mp_apply<mdarray_t,
    mp_append<
        mp_list<std::remove_all_extents_t<T>>,
        mp_transform_q<
            mp_bind<mp_extent, T, _1>,
            mp_iota_c<std::rank_v<T>>>
        >>;

Это тот же алгоритм, что и раньше, за исключением mp_iota_c<std::rank_v<T>> для получения последовательности индексов экстентов (вместо std::make_index_sequence) и затем mp_transform_q для получения n-го экстента (вместо использования его непосредственно в расширение пакета).

В этом случае для int[5][12] мы создаем mp_list<int, mp_size_t<5>, mp_size_t<12>> (потому что мы все типы, без значений), а затем mp_apply превращает это в mdarray_t<...>, которое превращает его в {{X4 }}.

3
Barry 8 Апр 2021 в 22:11

Я хотел бы вывести размеры встроенного массива в N и вернуть соответствующий mdarray.

Может быть ... с небольшой рекурсией ...

template <std::size_t ... Ns, typename T>
constexpr mdarray<std::remove_cv_t<T>, Ns...> get_mdarray_t (T const &)
 { return {}; }

template <std::size_t ... Ns, typename T, std::size_t N>
constexpr auto get_mdarray_t (T const (&arr)[N])
 { return get_mdarray_t<Ns..., N>(arr[0]); }

Вы можете построить using, который может быть полезным

template <typename T>
using mdarray_t = decltype(get_mdarray_t<>(std::declval<T>()));

Ниже приведен пример полной компиляции C ++ 11

#include <utility>

template <typename, std::size_t...>
struct mdarray
 { };

template <std::size_t ... Ns, typename T>
constexpr mdarray<std::remove_cv_t<T>, Ns...> get_mdarray_t (T const &)
 { return {}; }

template <std::size_t ... Ns, typename T, std::size_t N>
constexpr auto get_mdarray_t (T const (&arr)[N])
 { return get_mdarray_t<Ns..., N>(arr[0]); }

template <typename T>
using mdarray_t = decltype(get_mdarray_t<>(std::declval<T>()));

int main ()
 {
   using A0 = int;
   using A1 = int[2u];
   using A2 = int[2u][3u];
   using A3 = int[2u][3u][5u];

   using T0 = mdarray_t<A0>;
   using T1 = mdarray_t<A1>;
   using T2 = mdarray_t<A2>;
   using T3 = mdarray_t<A3>;

   using U0 = mdarray<int> ;
   using U1 = mdarray<int, 2u>;
   using U2 = mdarray<int, 2u, 3u>;
   using U3 = mdarray<int, 2u, 3u, 5u>;

   static_assert( std::is_same<T0, U0>::value, "!" );
   static_assert( std::is_same<T1, U1>::value, "!" );
   static_assert( std::is_same<T2, U2>::value, "!" );
   static_assert( std::is_same<T3, U3>::value, "!" );
 }
1
max66 8 Апр 2021 в 22:16