fork download
  1. #include <iostream>
  2. #include <type_traits>
  3.  
  4. // Helper template; needs no definition since we never instantiate it.
  5. template <typename...> struct pack;
  6.  
  7. // Helper to allow us to obtain the last type from a pack.
  8. template <typename> struct last_type_in_pack;
  9.  
  10. template <typename T>
  11. struct last_type_in_pack<pack<T>>
  12. {
  13. typedef T type;
  14. };
  15.  
  16. template <typename First, typename... Types>
  17. struct last_type_in_pack<pack<First, Types...>>
  18. : public last_type_in_pack<pack<Types...>> { };
  19.  
  20. // We need another helper to allow us to "peel off" the last type from a pack,
  21. // turning pack<A, B, C> into pack<A, B> for example.
  22. template <typename, typename> struct remove_last_type_from_pack_impl;
  23.  
  24. template <typename... Types, typename LastType>
  25. struct remove_last_type_from_pack_impl<pack<Types...>, pack<LastType>>
  26. {
  27. typedef pack<Types...> type;
  28. };
  29.  
  30. template <typename... TS1, typename T2, typename... TS2>
  31. struct remove_last_type_from_pack_impl<pack<TS1...>, pack<T2, TS2...>>
  32. : public remove_last_type_from_pack_impl<pack<TS1..., T2>, pack<TS2...>> { };
  33.  
  34. template <typename>
  35. struct remove_last_type_from_pack;
  36.  
  37. template <typename... Types>
  38. struct remove_last_type_from_pack<pack<Types...>>
  39. : public remove_last_type_from_pack_impl<pack<>, pack<Types...>> { };
  40.  
  41. // Leave this undefined. It will cause invalid instantiations to fail since it's an
  42. // incomplete type. All of our intended instantiations will be covered by partial
  43. // specializations below.
  44. template <typename...> struct Object;
  45.  
  46. // Partial specialization allowing "double-ended" packs, and requiring at least one
  47. // parent type and one child type. (FirstParent exists solely to enforce that there
  48. // is at least one parent type.)
  49. template <typename FirstParent, typename... ParentTypes,
  50. typename T,
  51. typename FirstChild, typename... ChildTypes>
  52. struct Object<pack<FirstParent, ParentTypes...>, T, pack<FirstChild, ChildTypes...>>
  53. {
  54. // We'll shift the packs around T to define our child and parent types:
  55. typedef Object<pack<FirstParent, ParentTypes..., T>,
  56. FirstChild,
  57. pack<ChildTypes...>> child_type;
  58.  
  59. typedef Object<
  60. typename remove_last_type_from_pack<pack<FirstParent, ParentTypes...>>::type,
  61. typename last_type_in_pack<pack<FirstParent, ParentTypes...>>::type,
  62. pack<T, FirstChild, ChildTypes...>> parent_type;
  63.  
  64. T item;
  65. child_type * child;
  66. parent_type * parent;
  67. };
  68.  
  69. // Now we need specializations for parent-less and child-less.
  70.  
  71. // Parent-less:
  72. template <typename T, typename FirstChild, typename... ChildTypes>
  73. struct Object<pack<>, T, pack<FirstChild, ChildTypes...>>
  74. {
  75. typedef Object<pack<T>, FirstChild, pack<ChildTypes...>> child_type;
  76.  
  77. T item;
  78. child_type * child;
  79. };
  80.  
  81. // Child-less. As before, FirstParent just ensures that we have at least one parent
  82. // type.
  83. template <typename FirstParent, typename... ParentTypes, typename T>
  84. struct Object<pack<FirstParent, ParentTypes...>, T, pack<>>
  85. {
  86. typedef Object<
  87. typename remove_last_type_from_pack<pack<FirstParent, ParentTypes...>>::type,
  88. typename last_type_in_pack<pack<FirstParent, ParentTypes...>>::type,
  89. pack<T>> parent_type;
  90.  
  91. T item;
  92. parent_type * parent;
  93. };
  94.  
  95. // Note that Object<pack<>, T, pack<>> can't be instantiated since no specialization
  96. // matches it, and the base template isn't defined. This type doesn't really make
  97. // much sense, IMO, but you can specialize Object for it if you want:
  98. //
  99. // template <typename T>
  100. // struct Object<pack<>, T, pack<>> { T item; };
  101.  
  102. template <typename Arg, typename... Rest>
  103. using ObjectWithNoParent = Object<pack<>, Arg, pack<Rest...>>;
  104.  
  105. int main() {
  106. Object<pack<>, int, pack<double, char, float, long>> a;
  107. Object<pack<int>, double, pack<char, float, long>> b;
  108. Object<pack<int, double>, char, pack<float, long>> c;
  109. Object<pack<int, double, char>, float, pack<long>> d;
  110. Object<pack<int, double, char, float>, long, pack<>> e;
  111.  
  112. static_assert(std::is_same<
  113. typename Object<pack<int, double>, char, pack<float, long>>::parent_type,
  114. Object<pack<int>, double, pack<char, float, long>>
  115. >::value, "parent types match");
  116.  
  117. static_assert(std::is_same<
  118. typename Object<pack<int, double>, char, pack<float, long>>::child_type,
  119. Object<pack<int, double, char>, float, pack<long>>
  120. >::value, "child types match");
  121.  
  122. // your code goes here
  123. return 0;
  124. }
Success #stdin #stdout 0s 3092KB
stdin
Standard input is empty
stdout
Standard output is empty