模板类型

时间:2017-10-17 20:36:34

标签: c++ templates variadic-templates c++17 template-meta-programming

鉴于

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的模板类型accumulated_sumstemplate <typename U, U...> class的{​​{1}}略有不同。否则,我必须分别定义这两个类,即使它们的定义基本相同。对于这两个类,应该有一些方法来定义它一次。这是我对这两个类的完全编译代码,你可以看到它们在代码中基本相同。

accumulated

2 个答案:

答案 0 :(得分:1)

如果您接受传递Q<>而不是Qstd::integer_sequence<int>(或std::integer_sequence<std::size_t>)而不是std::integer_sequence(因此模板类型而不是模板-template type)你可以在底部分叉案例(有或没有第一个类型的模板)(参见下面的例子中的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);
 }

答案 1 :(得分:1)

在调整max66的解决方案时,我允许PyQt4accumulated<std::integer_sequence<T, 1,2,3,4,5>>::type,其中T是任何整数类型。避免了重复实施。以下编译与GCC 7.2:

std::integer_sequence<T, 1,3,6,10,15>

更新:感谢max66的想法,我已经进一步推广到任意数量的序列:https://ideone.com/FBWApu 代码用GCC 7.2编译,但是由于它只使用C ++ 14而失败了。