C++ 基于另一个可变参数包查找可变数据包的收缩

C++ 基于另一个可变参数包查找可变数据包的收缩,c++,c++11,multidimensional-array,template-meta-programming,C++,C++11,Multidimensional Array,Template Meta Programming,我正在研究一个静态多维数组压缩框架,我遇到了一个有点难以解释的问题,但我会尽我所能。假设我们有一个N维数组类 template<typename T, int ... dims> class Array {} 我现在有一个函数construction,它的签名应该如下所示 template<T, int ... Dims, int ... Idx, typename std::enable_if<sizeof...(Dims)==sizeof...(Idx),bool

我正在研究一个静态多维数组压缩框架,我遇到了一个有点难以解释的问题,但我会尽我所能。假设我们有一个
N
维数组类

template<typename T, int ... dims>
class Array {}
我现在有一个函数
construction
,它的签名应该如下所示

template<T, int ... Dims, int ... Idx, 
typename std::enable_if<sizeof...(Dims)==sizeof...(Idx),bool>::type=0>
Array<T,apply_to_dims<Dims...,do_contract<Idx...>>> 
contraction(const Indices<Idx...> &idx, const Array<T,Dims...> &a)
因此,本质上,给定
Idx…
Dims…
两者大小相同,检查
Idx…
中的哪些值相等,获取它们出现的位置,并删除
Dims…
中的相应条目(位置)。这本质上是一个问题

数组收缩规则:

  • 索引的参数数量和数组的维度/秩应该相同,即
    sizeof…(Idx)==sizeof…(Dims)
  • Idx
    dim
    之间存在一对一的对应关系,即如果我们有
    索引
    数组
    0
    映射到
    4
    1
    映射到
    5
    2
    映射到
    6
  • 如果
    Idx
    中存在相同/相等的值,则意味着收缩,这意味着
    Dims
    中的相应维度应该消失,例如,如果我们有
    索引
    数组
    ,然后
    0==0
    以及这些值映射到的
    4
    4
    的相应维度都需要消失,结果数组应该是
    array
  • 如果
    Idx
    具有相同的值,但相应的
    Dims
    不匹配,则应触发编译时错误,例如,
    索引
    数组
    ,因为
    4=5
    ,同样的
    索引
    也不可能像
    4=6
    ,这将导致
  • 不同维度的数组不可能收缩,例如,
    Array
    不能以任何方式收缩
  • 只要相应的
    Dims
    也匹配,则
    Idx允许多对、三元组、四元组等,例如
    索引将收缩为
    数组,前提是输入数组为
    数组

  • 我对元编程的了解并没有达到实现此功能的程度,但我希望我已经明确了意图,以便有人能引导我朝着正确的方向前进。

    这是一个混乱,但我认为它做了您希望它做的事情。几乎可以肯定的是,可以对此进行许多简化,但这是我第一次通过测试。请注意,这并没有实现收缩,只是确定了应该是什么类型。如果这不是你需要的,我提前道歉

    #include <type_traits>
    
    template <std::size_t...>
    struct Indices {};
    
    template <typename, std::size_t...>
    struct Array {};
    
    // Count number of 'i' in 'rest...', base case
    template <std::size_t i, std::size_t... rest>
    struct Count : std::integral_constant<std::size_t, 0>
    {};
    
    // Count number of 'i' in 'rest...', inductive case
    template <std::size_t i, std::size_t j, std::size_t... rest>
    struct Count<i, j, rest...> :
        std::integral_constant<std::size_t,
                               Count<i, rest...>::value + ((i == j) ? 1 : 0)>
    {};
    
    // Is 'i' contained in 'rest...'?
    template <std::size_t i, std::size_t... rest>
    struct Contains :
        std::integral_constant<bool, (Count<i, rest...>::value > 0)>
    {};
    
    
    // Accumulation of counts of indices in all, base case
    template <typename All, typename Remainder,
              typename AccIdx, typename AccCount>
    struct Counts {
        using indices = AccIdx;
        using counts = AccCount;
    };
    
    // Accumulation of counts of indices in all, inductive case
    template <std::size_t... all, std::size_t i, std::size_t... rest,
              std::size_t... indices, std::size_t... counts>
    struct Counts<Indices<all...>, Indices<i, rest...>,
                  Indices<indices...>, Indices<counts...>>
        : std::conditional<Contains<i, indices...>::value,
                           Counts<Indices<all...>, Indices<rest...>,
                                  Indices<indices...>,
                                  Indices<counts...>>,
                           Counts<Indices<all...>, Indices<rest...>,
                                  Indices<indices..., i>,
                                  Indices<counts...,
                                          Count<i, all...>::value>>>::type
    {};
    
    // Get value in From that matched the first value of Idx that matched idx
    template <std::size_t idx, typename Idx, typename From>
    struct First : std::integral_constant<std::size_t, 0>
    {};
    template <std::size_t i, std::size_t j, std::size_t k,
              std::size_t... indices, std::size_t... values>
    struct First<i, Indices<j, indices...>, Indices<k, values...>>
        : std::conditional<i == j,
                           std::integral_constant<std::size_t, k>,
                           First<i, Indices<indices...>,
                                 Indices<values...>>>::type
    {};
    
    // Return whether all values in From that match Idx being idx are tgt
    template <std::size_t idx, std::size_t tgt, typename Idx, typename From>
    struct AllMatchTarget : std::true_type
    {};
    template <std::size_t idx, std::size_t tgt,
              std::size_t i, std::size_t j,
              std::size_t... indices, std::size_t... values>
    struct AllMatchTarget<idx, tgt,
                          Indices<i, indices...>, Indices<j, values...>>
        : std::conditional<i == idx && j != tgt, std::false_type,
                           AllMatchTarget<idx, tgt, Indices<indices...>,
                                          Indices<values...>>>::type
    {};
    
    /* Generate the dimensions, given the counts, indices, and values */
    template <typename Counts, typename Indices,
              typename AllIndices, typename Values, typename Accum>
    struct GenDims;
    
    template <typename A, typename V, typename R>
    struct GenDims<Indices<>, Indices<>, A, V, R> {
        using type = R;
    };
    template <typename T, std::size_t i, std::size_t c,
              std::size_t... counts, std::size_t... indices,
              std::size_t... dims, typename AllIndices, typename Values>
    struct GenDims<Indices<c, counts...>, Indices<i, indices...>,
                   AllIndices, Values, Array<T, dims...>>
    {
        static constexpr auto value = First<i, AllIndices, Values>::value;
        static_assert(AllMatchTarget<i, value, AllIndices, Values>::value,
                      "Index doesn't correspond to matching dimensions");
        using type = typename GenDims<
            Indices<counts...>, Indices<indices...>,
            AllIndices, Values,
            typename std::conditional<c == 1,
                                      Array<T, dims..., value>,
                                      Array<T, dims...>>::type>::type;
    };
    
    /* Put it all together */
    template <typename I, typename A>
    struct ContractionType;
    
    template <typename T, std::size_t... indices, std::size_t... values>
    struct ContractionType<Indices<indices...>, Array<T, values...>> {
        static_assert(sizeof...(indices) == sizeof...(values),
                       "Number of indices and dimensions do not match");
        using counts = Counts<Indices<indices...>,
                              Indices<indices...>,
                              Indices<>, Indices<>>;
        using type = typename GenDims<typename counts::counts,
                                      typename counts::indices,
                                      Indices<indices...>, Indices<values...>,
                                      Array<T>>::type;
    };
    
    static_assert(std::is_same<typename
                  ContractionType<Indices<0, 0>, Array<double, 3, 3>>::type,
                  Array<double>>::value, "");
    static_assert(std::is_same<typename
                  ContractionType<Indices<0, 1>, Array<double, 3, 3>>::type,
                  Array<double, 3, 3>>::value, "");
    static_assert(std::is_same<typename
                  ContractionType<Indices<0, 1, 0>, Array<double, 3, 4, 3>>::type,
                  Array<double, 4>>::value, "");
    static_assert(std::is_same<typename
                  ContractionType<Indices<0, 1, 0, 7, 7, 2>,
                  Array<double, 3, 4, 3, 5, 5, 6>>::type,
                  Array<double, 4, 6>>::value, "");
    
    // Errors appropriately when uncommented
    /* static_assert(std::is_same<typename */
    /*               ContractionType<Indices<10,10, 2, 3>, */
    /*               Array<double, 5,6,4,4>>::type, */
    /*               Array<double>::value, ""); */
    
    #包括
    样板
    结构索引{};
    样板
    结构数组{};
    //在“rest…”中计算“i”的数目,基本情况
    样板
    结构计数:标准::整型常量
    {};
    //计数“rest…”中的“i”个数,归纳情况
    样板
    结构计数:
    积分常数
    {};
    //“我”是否包含在“休息…”中?
    样板
    结构包含:
    标准:积分(常数0)>
    {};
    //所有基本情况下的指数计数累积
    样板
    结构计数{
    使用指数=AccIdx;
    使用计数=AccCount;
    };
    //在所有归纳情况下,指数计数的累积
    样板
    结构计数
    :std::conditional::type
    {};
    //从与Idx匹配的Idx的第一个值中获取值
    样板
    结构优先:std::整型常量
    {};
    样板
    结构优先
    :std::conditional::type
    {};
    //返回匹配Idx的Idx中的所有值是否为tgt
    样板
    struct AllMatchTarget:std::true\u类型
    {};
    样板
    结构AllMatchTarget
    :std::conditional::type
    {};
    /*根据计数、索引和值生成维度*/
    样板
    结构GenDims;
    样板
    结构GenDims{
    使用类型=R;
    };
    样板
    结构GenDims
    {
    静态constexpr auto value=First::value;
    静态断言(AllMatchTarget::value,
    “索引与匹配维度不对应”);
    使用type=typename<
    指数,指数,,
    联盟、价值观,
    typename std::conditional::type>::type;
    };
    /*把它们放在一起*/
    样板
    结构收缩型;
    样板
    结构收缩类型{
    静态断言(sizeof…(索引)=sizeof…(值),
    “索引数量和维度不匹配”);
    使用计数=计数;
    使用type=typename GenDims::type;
    };
    静态断言(std::is_same::value,“”);
    静态断言(std::is_same::value,“”);
    静态断言(std::is_same::value,“”);
    静态断言(std::is_same::value,“”);
    //未注释时的错误
    
    /*静态断言(std::is_same这是一个混乱,但我认为它做了您希望它做的事情。几乎可以肯定可以对此进行许多简化,但这是我第一次通过测试。请注意,这并没有实现收缩,只是确定了应该是什么类型。如果这不是您需要的,我在adv中道歉恩斯

    #include <type_traits>
    
    template <std::size_t...>
    struct Indices {};
    
    template <typename, std::size_t...>
    struct Array {};
    
    // Count number of 'i' in 'rest...', base case
    template <std::size_t i, std::size_t... rest>
    struct Count : std::integral_constant<std::size_t, 0>
    {};
    
    // Count number of 'i' in 'rest...', inductive case
    template <std::size_t i, std::size_t j, std::size_t... rest>
    struct Count<i, j, rest...> :
        std::integral_constant<std::size_t,
                               Count<i, rest...>::value + ((i == j) ? 1 : 0)>
    {};
    
    // Is 'i' contained in 'rest...'?
    template <std::size_t i, std::size_t... rest>
    struct Contains :
        std::integral_constant<bool, (Count<i, rest...>::value > 0)>
    {};
    
    
    // Accumulation of counts of indices in all, base case
    template <typename All, typename Remainder,
              typename AccIdx, typename AccCount>
    struct Counts {
        using indices = AccIdx;
        using counts = AccCount;
    };
    
    // Accumulation of counts of indices in all, inductive case
    template <std::size_t... all, std::size_t i, std::size_t... rest,
              std::size_t... indices, std::size_t... counts>
    struct Counts<Indices<all...>, Indices<i, rest...>,
                  Indices<indices...>, Indices<counts...>>
        : std::conditional<Contains<i, indices...>::value,
                           Counts<Indices<all...>, Indices<rest...>,
                                  Indices<indices...>,
                                  Indices<counts...>>,
                           Counts<Indices<all...>, Indices<rest...>,
                                  Indices<indices..., i>,
                                  Indices<counts...,
                                          Count<i, all...>::value>>>::type
    {};
    
    // Get value in From that matched the first value of Idx that matched idx
    template <std::size_t idx, typename Idx, typename From>
    struct First : std::integral_constant<std::size_t, 0>
    {};
    template <std::size_t i, std::size_t j, std::size_t k,
              std::size_t... indices, std::size_t... values>
    struct First<i, Indices<j, indices...>, Indices<k, values...>>
        : std::conditional<i == j,
                           std::integral_constant<std::size_t, k>,
                           First<i, Indices<indices...>,
                                 Indices<values...>>>::type
    {};
    
    // Return whether all values in From that match Idx being idx are tgt
    template <std::size_t idx, std::size_t tgt, typename Idx, typename From>
    struct AllMatchTarget : std::true_type
    {};
    template <std::size_t idx, std::size_t tgt,
              std::size_t i, std::size_t j,
              std::size_t... indices, std::size_t... values>
    struct AllMatchTarget<idx, tgt,
                          Indices<i, indices...>, Indices<j, values...>>
        : std::conditional<i == idx && j != tgt, std::false_type,
                           AllMatchTarget<idx, tgt, Indices<indices...>,
                                          Indices<values...>>>::type
    {};
    
    /* Generate the dimensions, given the counts, indices, and values */
    template <typename Counts, typename Indices,
              typename AllIndices, typename Values, typename Accum>
    struct GenDims;
    
    template <typename A, typename V, typename R>
    struct GenDims<Indices<>, Indices<>, A, V, R> {
        using type = R;
    };
    template <typename T, std::size_t i, std::size_t c,
              std::size_t... counts, std::size_t... indices,
              std::size_t... dims, typename AllIndices, typename Values>
    struct GenDims<Indices<c, counts...>, Indices<i, indices...>,
                   AllIndices, Values, Array<T, dims...>>
    {
        static constexpr auto value = First<i, AllIndices, Values>::value;
        static_assert(AllMatchTarget<i, value, AllIndices, Values>::value,
                      "Index doesn't correspond to matching dimensions");
        using type = typename GenDims<
            Indices<counts...>, Indices<indices...>,
            AllIndices, Values,
            typename std::conditional<c == 1,
                                      Array<T, dims..., value>,
                                      Array<T, dims...>>::type>::type;
    };
    
    /* Put it all together */
    template <typename I, typename A>
    struct ContractionType;
    
    template <typename T, std::size_t... indices, std::size_t... values>
    struct ContractionType<Indices<indices...>, Array<T, values...>> {
        static_assert(sizeof...(indices) == sizeof...(values),
                       "Number of indices and dimensions do not match");
        using counts = Counts<Indices<indices...>,
                              Indices<indices...>,
                              Indices<>, Indices<>>;
        using type = typename GenDims<typename counts::counts,
                                      typename counts::indices,
                                      Indices<indices...>, Indices<values...>,
                                      Array<T>>::type;
    };
    
    static_assert(std::is_same<typename
                  ContractionType<Indices<0, 0>, Array<double, 3, 3>>::type,
                  Array<double>>::value, "");
    static_assert(std::is_same<typename
                  ContractionType<Indices<0, 1>, Array<double, 3, 3>>::type,
                  Array<double, 3, 3>>::value, "");
    static_assert(std::is_same<typename
                  ContractionType<Indices<0, 1, 0>, Array<double, 3, 4, 3>>::type,
                  Array<double, 4>>::value, "");
    static_assert(std::is_same<typename
                  ContractionType<Indices<0, 1, 0, 7, 7, 2>,
                  Array<double, 3, 4, 3, 5, 5, 6>>::type,
                  Array<double, 4, 6>>::value, "");
    
    // Errors appropriately when uncommented
    /* static_assert(std::is_same<typename */
    /*               ContractionType<Indices<10,10, 2, 3>, */
    /*               Array<double, 5,6,4,4>>::type, */
    /*               Array<double>::value, ""); */
    
    #包括
    样板
    结构索引{};
    样板
    结构数组{};
    //在“rest…”中计算“i”的数目,基本情况
    样板
    结构计数:标准::整型常量
    {};
    //计数“rest…”中的“i”个数,归纳情况
    样板
    结构计数:
    积分常数
    {};
    //“我”是否包含在“休息…”中?
    样板
    结构包含:
    标准:积分(常数0)>
    {};
    //所有基本情况下的指数计数累积
    样板
    结构计数{
    使用指数=AccIdx;
    使用计数=AccCount;
    };
    //在所有归纳情况下,指数计数的累积
    样板
    结构计数
    :std::conditional::type
    {};
    //从与Idx匹配的Idx的第一个值中获取值
    样板
    结构优先:std::整型常量
    {};
    T
    
    auto arr = contraction(Indices<0,0>, Array<double,3,3>) 
    // arr is Array<double> as both indices contract 0==0
    
    auto arr = contraction(Indices<0,1>, Array<double,3,3>) 
    // arr is Array<double,3,3> as no contraction happens here, 0!=1
    
    auto arr = contraction(Indices<0,1,0>, Array<double,3,4,3>) 
    // arr is Array<double,4> as 1st and 3rd indices contract 0==0  
    
    auto arr = contraction(Indices<0,1,0,7,7,2>, Array<double,3,4,3,5,5,6>) 
    // arr is Array<double,4,6> as (1st and 3rd, 0==0) and (4th and 5th, 7==7) indices contract
    
    auto arr = contraction(Indices<10,10,2,3>, Array<double,5,6,4,4>
    // should not compile as contraction between 1st and 2nd arguments 
    // requested but dimensions don't match 5!=6
    
    // The parameters of Indices really do not matter as long as 
    // we can identify contractions. They are typically expressed as enums, I,J,K...
    
    #include <type_traits>
    
    template <std::size_t...>
    struct Indices {};
    
    template <typename, std::size_t...>
    struct Array {};
    
    // Count number of 'i' in 'rest...', base case
    template <std::size_t i, std::size_t... rest>
    struct Count : std::integral_constant<std::size_t, 0>
    {};
    
    // Count number of 'i' in 'rest...', inductive case
    template <std::size_t i, std::size_t j, std::size_t... rest>
    struct Count<i, j, rest...> :
        std::integral_constant<std::size_t,
                               Count<i, rest...>::value + ((i == j) ? 1 : 0)>
    {};
    
    // Is 'i' contained in 'rest...'?
    template <std::size_t i, std::size_t... rest>
    struct Contains :
        std::integral_constant<bool, (Count<i, rest...>::value > 0)>
    {};
    
    
    // Accumulation of counts of indices in all, base case
    template <typename All, typename Remainder,
              typename AccIdx, typename AccCount>
    struct Counts {
        using indices = AccIdx;
        using counts = AccCount;
    };
    
    // Accumulation of counts of indices in all, inductive case
    template <std::size_t... all, std::size_t i, std::size_t... rest,
              std::size_t... indices, std::size_t... counts>
    struct Counts<Indices<all...>, Indices<i, rest...>,
                  Indices<indices...>, Indices<counts...>>
        : std::conditional<Contains<i, indices...>::value,
                           Counts<Indices<all...>, Indices<rest...>,
                                  Indices<indices...>,
                                  Indices<counts...>>,
                           Counts<Indices<all...>, Indices<rest...>,
                                  Indices<indices..., i>,
                                  Indices<counts...,
                                          Count<i, all...>::value>>>::type
    {};
    
    // Get value in From that matched the first value of Idx that matched idx
    template <std::size_t idx, typename Idx, typename From>
    struct First : std::integral_constant<std::size_t, 0>
    {};
    template <std::size_t i, std::size_t j, std::size_t k,
              std::size_t... indices, std::size_t... values>
    struct First<i, Indices<j, indices...>, Indices<k, values...>>
        : std::conditional<i == j,
                           std::integral_constant<std::size_t, k>,
                           First<i, Indices<indices...>,
                                 Indices<values...>>>::type
    {};
    
    // Return whether all values in From that match Idx being idx are tgt
    template <std::size_t idx, std::size_t tgt, typename Idx, typename From>
    struct AllMatchTarget : std::true_type
    {};
    template <std::size_t idx, std::size_t tgt,
              std::size_t i, std::size_t j,
              std::size_t... indices, std::size_t... values>
    struct AllMatchTarget<idx, tgt,
                          Indices<i, indices...>, Indices<j, values...>>
        : std::conditional<i == idx && j != tgt, std::false_type,
                           AllMatchTarget<idx, tgt, Indices<indices...>,
                                          Indices<values...>>>::type
    {};
    
    /* Generate the dimensions, given the counts, indices, and values */
    template <typename Counts, typename Indices,
              typename AllIndices, typename Values, typename Accum>
    struct GenDims;
    
    template <typename A, typename V, typename R>
    struct GenDims<Indices<>, Indices<>, A, V, R> {
        using type = R;
    };
    template <typename T, std::size_t i, std::size_t c,
              std::size_t... counts, std::size_t... indices,
              std::size_t... dims, typename AllIndices, typename Values>
    struct GenDims<Indices<c, counts...>, Indices<i, indices...>,
                   AllIndices, Values, Array<T, dims...>>
    {
        static constexpr auto value = First<i, AllIndices, Values>::value;
        static_assert(AllMatchTarget<i, value, AllIndices, Values>::value,
                      "Index doesn't correspond to matching dimensions");
        using type = typename GenDims<
            Indices<counts...>, Indices<indices...>,
            AllIndices, Values,
            typename std::conditional<c == 1,
                                      Array<T, dims..., value>,
                                      Array<T, dims...>>::type>::type;
    };
    
    /* Put it all together */
    template <typename I, typename A>
    struct ContractionType;
    
    template <typename T, std::size_t... indices, std::size_t... values>
    struct ContractionType<Indices<indices...>, Array<T, values...>> {
        static_assert(sizeof...(indices) == sizeof...(values),
                       "Number of indices and dimensions do not match");
        using counts = Counts<Indices<indices...>,
                              Indices<indices...>,
                              Indices<>, Indices<>>;
        using type = typename GenDims<typename counts::counts,
                                      typename counts::indices,
                                      Indices<indices...>, Indices<values...>,
                                      Array<T>>::type;
    };
    
    static_assert(std::is_same<typename
                  ContractionType<Indices<0, 0>, Array<double, 3, 3>>::type,
                  Array<double>>::value, "");
    static_assert(std::is_same<typename
                  ContractionType<Indices<0, 1>, Array<double, 3, 3>>::type,
                  Array<double, 3, 3>>::value, "");
    static_assert(std::is_same<typename
                  ContractionType<Indices<0, 1, 0>, Array<double, 3, 4, 3>>::type,
                  Array<double, 4>>::value, "");
    static_assert(std::is_same<typename
                  ContractionType<Indices<0, 1, 0, 7, 7, 2>,
                  Array<double, 3, 4, 3, 5, 5, 6>>::type,
                  Array<double, 4, 6>>::value, "");
    
    // Errors appropriately when uncommented
    /* static_assert(std::is_same<typename */
    /*               ContractionType<Indices<10,10, 2, 3>, */
    /*               Array<double, 5,6,4,4>>::type, */
    /*               Array<double>::value, ""); */
    
    // is ind[i] unique in ind?
    template<size_t N>
    constexpr bool is_uniq(const int (&ind)[N], size_t i, size_t cur = 0){
        return cur == N ? true : 
               (cur == i || ind[cur] != ind[i]) ? is_uniq(ind, i, cur + 1) : false;
    }
    
    // For every i where ind[i] == index, is dim[i] == dimension?
    template<size_t N>
    constexpr bool check_all_eq(int index, int dimension,
                                const int (&ind)[N], const int (&dim)[N], size_t cur = 0) {
        return cur == N ? true :
               (ind[cur] != index || dim[cur] == dimension) ? 
                    check_all_eq(index, dimension, ind, dim, cur + 1) : false;
    }
    
    // if position i should be contracted away, return -1, otherwise return dim[i].
    // triggers a compile-time error when used in a constant expression on mismatch.
    template<size_t N>
    constexpr int calc(size_t i, const int (&ind)[N], const int (&dim)[N]){
        return is_uniq(ind, i) ? dim[i] :
               check_all_eq(ind[i], dim[i], ind, dim) ? -1 : throw "dimension mismatch";
    }
    
    template<class Ind, class... Inds>
    struct concat { using type = Ind; };
    template<int... I1, int... I2, class... Inds>
    struct concat<Indices<I1...>, Indices<I2...>, Inds...>
        :  concat<Indices<I1..., I2...>, Inds...> {};
    
    // filter out all instances of I from Is...,
    // return the rest as an Indices    
    template<int I, int... Is>
    struct filter
        :  concat<typename std::conditional<Is == I, Indices<>, Indices<Is>>::type...> {};
    
    template<class Ind, class Arr, class Seq>
    struct contraction_impl;
    
    template<class T, int... Ind, int... Dim, size_t... Seq>
    struct contraction_impl<Indices<Ind...>, Array<T, Dim...>, std::index_sequence<Seq...>>{
        static constexpr int ind[] = { Ind... };
        static constexpr int dim[] = { Dim... };
        static constexpr int result[] = {calc(Seq, ind, dim)...};
    
        template<int... Dims>
        static auto unpack_helper(Indices<Dims...>) -> Array<T, Dims...>;
    
        using type = decltype(unpack_helper(typename filter<-1,  result[Seq]...>::type{}));
    };
    
    
    template<class T, int ... Dims, int ... Idx, 
    typename std::enable_if<sizeof...(Dims)==sizeof...(Idx),bool>::type=0>
    typename contraction_impl<Indices<Idx...>, Array<T,Dims...>, 
                              std::make_index_sequence<sizeof...(Dims)>>::type
    contraction(const Indices<Idx...> &idx, const Array<T,Dims...> &a);