Создание обёртки массива C (лучше std :: array?) - PullRequest
0 голосов
/ 02 декабря 2018

Вот простой пример двумерного массива в стиле C:

int c[2][2] = {
    { 1, 2 },
    { 3, 4 }
};

Если я хочу, чтобы это было std::array, я должен использовать это:

std::array<std::array<int, 2>, 2> c = {
    { { 1, 2 } },
    { { 3, 4 } }
};

объявление более сложное, и мне нужно использовать дополнительные { } для инициализации.

Можно ли создать упаковщик массива в стиле C, с помощью которого я могу это сделать?

my_array<int, 2, 2> c = {
    { 1, 2 },
    { 3, 4 }
};

Таким образом, объявление проще, и нет необходимости в дополнительных { }.

Если создание чего-либо подобного возможно, будет ли это решение иметь некоторые недостатки по сравнению с std::array?


Мне удалось сделать это:

template <typename T, std::size_t ...S>
struct ArrayTypeHelper;

template <typename T, std::size_t HEAD, std::size_t ...TAIL>
struct ArrayTypeHelper<T, HEAD, TAIL...> {
    using Type = typename ArrayTypeHelper<T, TAIL...>::Type[HEAD];
};
template <typename T, std::size_t HEAD>
struct ArrayTypeHelper<T, HEAD> {
    using Type = T[HEAD];
};

template <typename T, std::size_t ...S>
struct my_array {
    typename ArrayTypeHelper<T, S...>::Type data;
};

Но для этого все еще нужны дополнительные { }:

my_array<int, 2, 2> b = { {
    { 1, 2 },
    { 3, 4 }
} };

1 Ответ

0 голосов
/ 02 декабря 2018

Проблема в том, что член массива c всегда рассматривается алгоритмом исключения скобок как единая сущность.Если внутренний инициализатор начинается с фигурной скобки, алгоритм ожидает список инициализатора с одним элементом.Таким образом, решение состоит в том, чтобы определить обертку Carray таким образом, чтобы алгоритм исключения скобок знал, сколько элементов объединено оберткой.

Для этого единственное решение, которое я вижу, состоит в том, чтобы смоделировать массив посредством множественного наследования:

#include <utility>
using namespace std;

template<class T,size_t DeDuplicate>
struct holder{
  T val;
  };

template<class T,class IndSeq>
struct carray_wrapper_b;

template<class T,size_t...Is>
struct carray_wrapper_b<T,index_sequence<Is...>>
  :holder<T,Is>...
  {   };

template<class T,size_t I,size_t...Is>
struct make_carray_{
  using type = carray_wrapper_b<typename make_carray_<T,Is...>::type
                               ,make_index_sequence<I>>;
  };
template<class T,size_t I>
struct make_carray_<T,I>{
  using type = carray_wrapper_b<T,make_index_sequence<I>>;
  };

template<class T,size_t...Is>
using carray_wrapper = typename make_carray_<T,Is...>::type;

carray_wrapper<int,2,2>  x = { {1,2},{3,4}};
carray_wrapper<int,2,2>  y = { 1,2,3,4};

Эта обертка массива также может использоваться только для целей инициализации:

template<class T,size_t I,size_t...Is>

struct carray{
  carray(initializer_list<T>);
  carray(initializer_list<carray_wrapper<T,Is...>>);
  };

carray<int,2,2,3> arr{1,2,3,4,5,6,7};
carray<int,2,2,3> arr2{{1,2},{3,4}};
carray<int,2,2,3> arr3{{{1,2},{3,4}},{1,2}};
...