0

鑑於繼承在模板類型略有變化後traits類

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_sums類的一些繼承方案定義accumulated類?它們的操作方式完全相同,唯一不同的是模板類型template <T...> class對於accumulated_sums而對於accumulated稍有不同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 
} 
+0

@ max66 [在C++ 17中編譯得很好](https://godbolt.org/g/5tKv7Z) – Justin

+0

@Justin - thanks; right:C++ 17 – max66

回答

1

如果接受通過Q<>,而不是Qstd::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>>::typestd::integer_sequence<T, 1,3,6,10,15>,其中T是任何整型?

我看過你的解決方案,我已經準備了一個又一個,不是一個很大的不同:扔了舊Z,我已經與std::integer_sequence而不是你的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); 
} 
+0

以及如何分解案例,以便'accumulate > :: type'是'std :: integer_sequence ',其中'T'是任何整型? 'template class Z,T首先, T ...其餘,typename C> struct cumulative ,C>從什麼繼承(不重複實現)? – prestokeys

+0

好的,我找到了你想要的解決方案(不需要重複執行)。我將其添加爲答案。 – prestokeys

+0

@prestokeys - 回答修改,但我的改進解決方案基本上相當於您的 – max66

1

在適應max66溶液,我允許的,例如,accumulated<std::integer_sequence<T, 1,2,3,4,5>>::typestd::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。