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

模板类型稍有更改后继承traits类

  •  0
  • prestokeys  · 技术社区  · 8 年前

    鉴于

    template <int...> struct Z;   template <int...> struct Q;
    template <std::size_t...> struct I;
    

    假设我们想要

    accumulated_sums<Z<1,2,3,4,5>, Q>::type
    

    成为

    Q<1,3,6,10,15>
    

    和

    accumulated<I<1,2,3,4,5>, std::integer_sequence>::type
    

    成为

    std::index_sequence<1,3,6,10,15>
    

    有没有办法定义 accumulated 通过某种继承方案从 accumulated_sums template <T...> class 对于 累计金额 与略有不同 template <typename U, U...> class 对于 . 否则,我必须分别定义这两个类,即使它们的定义基本相同。应该有某种方法为这两个类定义一次。这是我为这两个类编写的完整代码,您可以看到它们在代码上基本相同。

    #include <iostream>
    #include <type_traits>
    #include <utility>
    
    namespace detail {
        template <typename Pack> struct sequence_traits;
    
        template <typename T, template <T...> class Z, T... Is>
        struct sequence_traits<Z<Is...>> {
            using type = T;
            template <T... Js>
            using templ_type = Z<Js...>;
        };
    }
    
    // accumulated_sums
    template <typename T, typename Output, template <T...> class, T...> struct accumulated_sums_h;
    
    template <typename T, template <T...> class Z, template <T...> class Q, T Sum, T... Is>
    struct accumulated_sums_h<T, Z<Sum, Is...>, Q> {
        using type = Q<Is..., Sum>;
    };
    
    template <typename T, template <T...> class Z, T Sum, T... Is, template <T...> class Q, T Next, T... Rest>
    struct accumulated_sums_h<T, Z<Sum, Is...>, Q, Next, Rest...> :
        accumulated_sums_h<T, Z<Sum + Next, Is..., Sum>, Q, Rest...> {};
    
    template <typename Sequence,
        template <typename detail::sequence_traits<Sequence>::type...> class = detail::sequence_traits<Sequence>::template templ_type>
        struct accumulated_sums;
    
    template <typename T, template <T...> class Z, T First, T... Rest, template <T...> class Q>
    struct accumulated_sums<Z<First, Rest...>, Q> :
        accumulated_sums_h<T, Z<First>, Q, Rest...> {};
    
    // accumulated
    template <typename T, typename Output, template <typename U, U...> class, T...> struct accumulated_h;
    
    template <typename T, template <T...> class Z, template <typename U, U...> class Q, T Sum, T... Is>
    struct accumulated_h<T, Z<Sum, Is...>, Q> {
        using type = Q<T, Is..., Sum>;
    };
    
    template <typename T, template <T...> class Z, T Sum, T... Is, template <typename U, U...> class Q, T Next, T... Rest>
    struct accumulated_h<T, Z<Sum, Is...>, Q, Next, Rest...> :
        accumulated_h<T, Z<Sum + Next, Is..., Sum>, Q, Rest...> {};
    
    template <typename Sequence, template <typename U, U...> class Q> struct accumulated;
    
    template <typename T, template <T...> class Z, T First, T... Rest, template <typename U, U...> class Q>
    struct accumulated<Z<First, Rest...>, Q> :
        accumulated_h<T, Z<First>, Q, Rest...> {};
    
    // Testing
    template <int...> struct Z;
    template <int...> struct Q;
    template <std::size_t...> struct I;
    
    int main() {
        std::cout << std::boolalpha << std::is_same<
            accumulated_sums<Z<1,2,3,4,5>, Q>::type,
            Q<1,3,6,10,15>
        >::value << '\n';  // true
    
        std::cout << std::is_same<
            accumulated_sums<Z<1,2,3,4,5>>::type,
            Z<1,3,6,10,15>
        >::value << '\n';  // true
    
        std::cout << std::is_same<
            accumulated<Z<1,2,3,4,5>, std::integer_sequence>::type,
            std::integer_sequence<int, 1,3,6,10,15>
        >::value << '\n';  // true
    
        std::cout << std::is_same<
            accumulated<I<1,2,3,4,5>, std::integer_sequence>::type,
            std::index_sequence<1,3,6,10,15>
        >::value << '\n';  // true
    }
    
    2 回复  |  直到 8 年前
        1
  •  1
  •   max66    8 年前

    如果你接受通过 Q<> 而不是 Q 和 std::integer_sequence<int> (或 std::integer_sequence<std::size_t> )而不是 std::integer_sequence (因此使用模板类型而不是模板类型)您可以在底部分叉案例(有或没有第一个类型模板)(请参见 accumulated_h2

    所以你可以使用 accumulated 对于这两种情况,都要离开 accumulated_sum .

    下面是一个完整的工作示例。

    #include <type_traits>
    #include <utility>
    
    namespace detail
     {
       template <typename Pack>
       struct sequence_traits;
    
       template <typename T, template <T...> class Z, T... Is>
       struct sequence_traits<Z<Is...>>
        { using templ_empty = Z<>; };
     }
    
    // accumulated
    
    template <typename T, typename, T...>
    struct accumulated_h2;
    
    template <typename T, template <typename, T ...> class Q, T ... Ts>
    struct accumulated_h2<T, Q<T>, Ts...>
     { using type = Q<T, Ts...>; };
    
    template <typename T, template <T ...> class Q, T ... Ts>
    struct accumulated_h2<T, Q<>, Ts...>
     { using type = Q<Ts...>; };
    
    template <typename T, typename, typename, T...>
    struct accumulated_h;
    
    template <typename T, template <T...> class Z, typename C, T Sum, T... Is>
    struct accumulated_h<T, Z<Sum, Is...>, C>
     { using type = typename accumulated_h2<T, C, Is..., Sum>::type; };
    
    template <typename T, template <T...> class Z, T Sum, T... Is,
              typename C, T Next, T... Rest>
    struct accumulated_h<T, Z<Sum, Is...>, C, Next, Rest...>
       : accumulated_h<T, Z<Sum + Next, Is..., Sum>, C, Rest...>
     { };
    
    template <typename T,
              typename = typename detail::sequence_traits<T>::templ_empty>
    struct accumulated;
    
    template <typename T, template <T...> class Z, T First,
              T... Rest, typename C>
    struct accumulated<Z<First, Rest...>, C>
       : accumulated_h<T, Z<First>, C, Rest...>
     { };
    
    // Testing
    
    template <int...>
    struct Z;
    
    template <int...>
    struct Q;
    
    template <std::size_t...>
    struct I;
    
    int main ()
     {
       static_assert(std::is_same<
          accumulated<Z<1,2,3,4,5>, Q<>>::type,
          Q<1,3,6,10,15>>::value, "!");
       static_assert(std::is_same<
          accumulated<Z<1,2,3,4,5>>::type,
          Z<1,3,6,10,15>>::value, "!");    
       static_assert(std::is_same<
          accumulated<Z<1,2,3,4,5>, std::integer_sequence<int>>::type,
          std::integer_sequence<int, 1,3,6,10,15>>::value, "!");
       static_assert(std::is_same<
          accumulated<I<1,2,3,4,5>, std::integer_sequence<std::size_t>>::type,
          std::index_sequence<1,3,6,10,15>>::value, "!");
     }
    

    --编辑--

    OP提问

    以及如何分叉箱子,以便 accumulated<std::integer_sequence<T, 1,2,3,4,5>>::type 是 std::integer_sequence<T, 1,3,6,10,15> 哪里 T 有积分类型吗?

    我看到了你的解决方案,我准备了另一个,没什么不同:扔掉旧的 Z ,我用 std::整数_序列 相反,你的 squeeze .

    以下是我的代码。

    #include <type_traits>
    #include <utility>
    
    namespace detail
     {
       template <typename Pack>
       struct sequence_traits;
    
       template <typename T, template <typename, T...> class Z, T... Is>
       struct sequence_traits<Z<T, Is...>>
        { using templ_empty = Z<T>; };
    
       template <typename T, template <T...> class Z, T... Is>
       struct sequence_traits<Z<Is...>>
        { using templ_empty = Z<>; };
     }
    
    // accumulated
    
    template <typename T, typename, T...>
    struct accumulated_h2;
    
    template <typename T, template <typename, T ...> class Q, T ... Ts>
    struct accumulated_h2<T, Q<T>, Ts...>
     { using type = Q<T, Ts...>; };
    
    template <typename T, template <T ...> class Q, T ... Ts>
    struct accumulated_h2<T, Q<>, Ts...>
     { using type = Q<Ts...>; };
    
    template <typename T, typename, typename, T...>
    struct accumulated_h;
    
    template <typename T, typename C, T Sum, T... Is>
    struct accumulated_h<T, std::integer_sequence<T, Sum, Is...>, C>
     { using type = typename accumulated_h2<T, C, Is..., Sum>::type; };
    
    template <typename T, T Sum, T... Is, typename C, T Next, T... Rest>
    struct accumulated_h<T, std::integer_sequence<T, Sum, Is...>, C, Next,
                         Rest...>
       : accumulated_h<T, std::integer_sequence<T, Sum + Next, Is..., Sum>,
                       C, Rest...>
     { };
    
    template <typename T,
              typename = typename detail::sequence_traits<T>::templ_empty>
    struct accumulated;
    
    template <typename T, template <T...> class Z, T First,
              T... Rest, typename C>
    struct accumulated<Z<First, Rest...>, C>
       : accumulated_h<T, std::integer_sequence<T, First>, C, Rest...>
     { };
    
    template <typename T, template <typename, T...> class Z, T First,
              T... Rest, typename C>
    struct accumulated<Z<T, First, Rest...>, C>
       : accumulated_h<T, std::integer_sequence<T, First>, C, Rest...>
     { };
    
    // Testing
    
    template <int...>
    struct Z;
    
    template <int...>
    struct Q;
    
    template <std::size_t...>
    struct I;
    
    int main ()
     {
       static_assert(std::is_same<
          accumulated<Z<1,2,3,4,5>, Q<>>::type,
          Q<1,3,6,10,15>>::value, "!");
       static_assert(std::is_same<
          accumulated<Z<1,2,3,4,5>>::type,
          Z<1,3,6,10,15>>::value, "!");    
       static_assert(std::is_same<
          accumulated<Z<1,2,3,4,5>, std::integer_sequence<int>>::type,
          std::integer_sequence<int, 1,3,6,10,15>>::value, "!");
       static_assert(std::is_same<
          accumulated<I<1,2,3,4,5>, std::integer_sequence<std::size_t>>::type,
          std::index_sequence<1,3,6,10,15>>::value, "!");
       static_assert(std::is_same<
          accumulated<std::index_sequence<1,2,3,4,5>>::type,
          std::index_sequence<1,3,6,10,15>>::value);
       static_assert(std::is_same<
          accumulated<std::index_sequence<1,2,3,4,5>, I<>>::type,
          I<1,3,6,10,15>>::value);
     }
    
        2
  •  1
  •   prestokeys    8 年前

    例如,在修改max66的解决方案时,我允许, accumulated<std::integer_sequence<T, 1,2,3,4,5>>::type 成为 std::integer_sequence<T, 1,3,6,10,15> ,其中T是任何积分类型。避免了重复实施。以下内容使用GCC 7.2编译:

    #include <type_traits>
    #include <utility>
    
    namespace detail {
       template <typename Pack>
       struct sequence_traits;
    
       template <typename T, template <T...> class Z, T... Is>
       struct sequence_traits<Z<Is...>>
        { using templ_empty = Z<>; };
    
       template <typename T, template <typename U, U...> class Z, T... Is>
       struct sequence_traits<Z<T, Is...>>
        { using templ_empty = Z<T>; };
     }
    
    // accumulated
    template <typename T, typename EmptyContainer, T...>
    struct accumulated_h2;
    
    template <typename T, template <typename U, U...> class Q, T ... Ts>
    struct accumulated_h2<T, Q<T>, Ts...>
     { using type = Q<T, Ts...>; };
    
    template <typename T, template <T...> class Q, T ... Ts>
    struct accumulated_h2<T, Q<>, Ts...>
     { using type = Q<Ts...>; };
    
    template <typename T, typename Sequence, typename, T...>
    struct accumulated_h;
    
    template <typename T, template <T...> class Z, typename EmptyContainer, T Sum, T... Is>
    struct accumulated_h<T, Z<Sum, Is...>, EmptyContainer>
     { using type = typename accumulated_h2<T, EmptyContainer, Is..., Sum>::type; };
    
    template <typename T, template <T...> class Z, T Sum, T... Is,
              typename EmptyContainer, T Next, T... Rest>
    struct accumulated_h<T, Z<Sum, Is...>, EmptyContainer, Next, Rest...>
       : accumulated_h<T, Z<Sum + Next, Is..., Sum>, EmptyContainer, Rest...>
     { };
    
    template <typename Sequence,
              typename = typename detail::sequence_traits<Sequence>::templ_empty>
    struct accumulated;
    
    template <typename T, template <T...> class Z, T First,
              T... Rest, typename EmptyContainer>
    struct accumulated<Z<First, Rest...>, EmptyContainer>
       : accumulated_h<T, Z<First>, EmptyContainer, Rest...>
     { };
    
    ////// Added //////
    template <typename T> struct squeeze {
        template <T... Is> struct Z;
        template <T... Is>
        using templ_type = Z<Is...>;
    };
    
    template <typename T, template <typename U, U...> class Z, T First,
              T... Rest, typename EmptyContainer>
    struct accumulated<Z<T, First, Rest...>, EmptyContainer>
       : accumulated_h<T, typename squeeze<T>::template templ_type<First>, EmptyContainer, Rest...>
     { };
    /////////
    
    // Testing
    template <int...>
    struct Z;
    
    template <int...>
    struct Q;
    
    template <std::size_t...>
    struct I;
    
    int main ()
     {
       static_assert(std::is_same<
          accumulated<Z<1,2,3,4,5>, Q<>>::type,
          Q<1,3,6,10,15>>::value);
       static_assert(std::is_same<
          accumulated<Z<1,2,3,4,5>>::type,
          Z<1,3,6,10,15>>::value);    
       static_assert(std::is_same<
          accumulated<Z<1,2,3,4,5>, std::integer_sequence<int>>::type,
          std::integer_sequence<int, 1,3,6,10,15>>::value);
       static_assert(std::is_same<
          accumulated<I<1,2,3,4,5>, std::integer_sequence<std::size_t>>::type,
          std::index_sequence<1,3,6,10,15>>::value);
    
        // Added
        static_assert(std::is_same<
          accumulated<std::index_sequence<1,2,3,4,5>>::type,
          std::index_sequence<1,3,6,10,15>>::value);    
     }
    

    更新:多亏了max66的想法,我将其推广到了任意数量的序列: https://ideone.com/FBWApu 代码使用GCC 7.2编译,但ideone失败,因为它只使用C++14。