代码之家  ›  专栏  ›  技术社区  ›  geza

创建C数组包装器(更好的std::array?)

  •  2
  • geza  · 技术社区  · 6 年前

    下面是一个简单的二维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::阵列 是吗?


    我已经做到了:

    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 回复  |  直到 6 年前
        1
  •  3
  •   Oliv    6 年前

    问题是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}};