转换嵌套包的每个内包

时间:2015-02-04 15:47:46

标签: c++ templates variadic

在这里,作为一个例子,我将尝试将包中的模板参数向左旋转N,但我希望这也完成嵌套包的每个内包。下面的代码只有在内包是包中的第一个类型时才有效,我需要知道如果它是嵌套的,如何检查包中的每个类型,然后将转换应用于每个类型。 TransformNestedPack是我正在努力的方向。 PackTransformation的原因是TransformNestedPack可以重复用于任何转换(轮换只是我使用的一个例子)。因此,我尝试使用常规转换TransformNestedPack来完善PackTransformation

#include <iostream>

// Rotating a pack N to the left.
template <int, typename> struct Rotate;

template <template <typename...> class P, typename First, typename... Rest>
struct Rotate<0, P<First, Rest...>> {
    using type = P<First, Rest...>;
};

template <int N, int K>
struct PositiveModulo : std::integral_constant<int, (N % K + K) % K> {};

template <int N, template <typename...> class P, typename First, typename... Rest>
struct Rotate<N, P<First, Rest...>> :
    Rotate<PositiveModulo<N-1, sizeof...(Rest)+1>::value, P<Rest..., First>> {};

enum {Rot, Rev, /* ... */};  // enum values for each type of pack transformation.

template <typename, int, int...> struct PackTransformation;

// Specializations of PackTransformation to carry out each type of pack transformation.
template <template <typename...> class P, int N, typename... Types>
struct PackTransformation<P<Types...>, Rot, N> {
    using type = typename Rotate<N, P<Types...>>::type;
};
// Similarly struct PackTransformation<P<Types...>, Rev> will reverse P<Types...>, etc...

// Attempt to have PackTransformation applied to each inner pack in a nested pack:
template <typename, int, int...> struct TransformNestedPack;

// Normal transformation, because the first type is not a pack:
template <template <typename...> class P, typename... Types, int N, int... Parameters>
struct TransformNestedPack<P<Types...>, N, Parameters...> : PackTransformation<P<Types...>, N, Parameters...> {};

// Specialization for when the first type is a pack:
template <template <typename...> class P, typename... Types, typename... Rest, int N, int... Parameters>
struct TransformNestedPack<P<P<Types...>, Rest...>, N, Parameters...> :
    PackTransformation<P<typename TransformNestedPack<P<Types...>, N, Parameters...>::type, Rest...>, N, Parameters...> {};
// The problem above is that it checks only the first type.  It needs to check EVERY type.

template <typename...> struct Pack {};

int main() {
    using NestedPack = Pack<Pack<int, double, char, long>, char, long, short>;
    PackTransformation<NestedPack, Rot, 2>::type a;  // Rotates NestedPack to the left by 2, but not the inner pack.
    std::cout << std::boolalpha << std::is_same< decltype(a),
        Pack<long, short, Pack<int, double, char, long>, char>
    >::value << std::endl;  // true

    TransformNestedPack<NestedPack, Rot, 2>::type b;
    std::cout << std::is_same< decltype(b),
        Pack<long, short, Pack<char, long, int, double>, char>
    >::value << std::endl;  // true
    // The above currently works only if there is one nested pack and that nested pack is the first type.
}

我只需要通过检查每种类型来概括上述内容,如果它是一个包,而不仅仅是第一个。

1 个答案:

答案 0 :(得分:2)

首先,不要将TransformNestedPack的主要模板保留为未定义,如果它不是包,则使其返回不变的类型:

template <typename T, int, int...> struct TransformNestedPack {
    using type = T; // do nothing for non-packs
};

然后转换包包括1)以递归方式将TransformNestedPack应用于包中的每个类型,以及2)将PackTransformation应用于生成的转换类型包本身。因此:

template <template <typename...> class P, typename... Types, int N, int... Parameters>
struct TransformNestedPack<P<Types...>, N, Parameters...> 
      : PackTransformation<P<typename TransformNestedPack<Types, N, Parameters...>::type...>, 
                             N, Parameters...> {};

Demo