fork download
  1. #include <tuple>
  2. #include <type_traits>
  3.  
  4. template <typename T>
  5. struct Identity { using type = T; };
  6.  
  7. // ExistsInPack
  8. template <typename T, typename Pack> struct ExistsInPack;
  9.  
  10. template <typename T, template <typename...> class P>
  11. struct ExistsInPack<T, P<>> : std::false_type {};
  12.  
  13. template <typename T, template <typename...> class P, typename First, typename... Rest>
  14. struct ExistsInPack<T, P<First, Rest...>> : ExistsInPack<T, P<Rest...>> {};
  15.  
  16. template <typename T, template <typename...> class P, typename... Rest>
  17. struct ExistsInPack<T, P<T, Rest...>> : std::true_type {};
  18.  
  19. // IsEmpty
  20. template <typename T>
  21. struct IsEmpty : std::false_type {};
  22.  
  23. template <template <typename...> class P>
  24. struct IsEmpty<P<>> : std::true_type {};
  25.  
  26. // Union of packs.
  27. template <typename, typename, typename> struct UnionHelper;
  28.  
  29. template <template <typename...> class P, typename... Types, typename... Accumulated>
  30. struct UnionHelper<P<Types...>, P<>, P<Accumulated...>> {
  31. using type = P<Accumulated...>;
  32. };
  33.  
  34. template <template <typename...> class P, typename First, typename... Rest, typename... Types, typename... Accumulated>
  35. struct UnionHelper<P<Types...>, P<First, Rest...>, P<Accumulated...>> : std::conditional_t<ExistsInPack<First, P<Types...>>::value,
  36. UnionHelper<P<Types...>, P<Rest...>, P<Accumulated...>>,
  37. UnionHelper<P<Types...>, P<Rest...>, P<Accumulated..., First>>
  38. > {};
  39.  
  40. template <typename...> struct Union;
  41.  
  42. template <>
  43. struct Union<> { using type = void; };
  44.  
  45. template <typename Pack>
  46. struct Union<Pack> : Identity<Pack> {};
  47.  
  48. template <typename Pack1, typename Pack2>
  49. struct Union<Pack1, Pack2> : UnionHelper<Pack1, Pack2, Pack1> {};
  50.  
  51. template <typename Pack1, typename Pack2, typename... Packs>
  52. struct Union<Pack1, Pack2, Packs...> : Union<typename Union<Pack1, Pack2>::type, Packs...> {};
  53.  
  54. // CombineLinks
  55. template <template <typename> class Link, template <typename...> class Combine, typename Pack> struct CombineLinks;
  56.  
  57. template <template <typename> class Link, template <typename...> class Combine, template <typename...> class P, typename... Ts>
  58. struct CombineLinks<Link, Combine, P<Ts...>> : Combine<Link<Ts>...> {}; // Right here! Link<Ts> must remove any member of that pack that is already in the union. This idea MIGHT work.
  59.  
  60. template <template <typename> class Link, template <typename...> class Combine, template <typename...> class P>
  61. struct CombineLinks<Link, Combine, P<>> : Identity <std::tuple<>> {};
  62.  
  63. // Network<T, Link, Combine> is the "combining" (specified by Combine) of all the links of T (specified by Link), and their links, and their links, etc... until there are no more links.
  64. template <template <typename> class Link, template <typename...> class Combine, typename...> struct NetworkHelper;
  65.  
  66. template <template <typename> class Link, template <typename...> class Combine, typename T, typename First, typename... Rest>
  67. using NetworkHelperAlias = std::conditional_t< IsEmpty<T>::value, Combine<First, Rest...>, NetworkHelper<Link, Combine, T, First, Rest...> >;
  68.  
  69. template <template <typename> class Link, template <typename...> class Combine, typename First, typename... Rest>
  70. struct NetworkHelper<Link, Combine, First, Rest...> : NetworkHelperAlias<Link, Combine, typename CombineLinks<Link, Combine, First>::type, First, Rest...> {};
  71.  
  72. template <typename T, template <typename> class Link, template <typename...> class Combine>
  73. using Network = NetworkHelper<Link, Combine, std::tuple<T>>;
  74.  
  75. // Detecting if the member type T::links exists in class T.
  76. template <typename T>
  77. using void_t = void;
  78.  
  79. template <typename T, typename = void>
  80. struct has_links_member : std::false_type {};
  81.  
  82. template <typename T>
  83. struct has_links_member<T, void_t<typename T::links>> : std::true_type {};
  84.  
  85. // LinkedTypes<T> is T::links if such a member type exists in T.
  86. template <typename T, bool HasLinksMember>
  87. struct LinkedTypesHelper : Identity <typename T::links> {};
  88.  
  89. template <typename T>
  90. struct LinkedTypesHelper<T, false> : Identity <std::tuple<>> {};
  91.  
  92. template <typename T>
  93. using LinkedTypes = typename LinkedTypesHelper<T, has_links_member<T>::value>::type;
  94.  
  95. // Template alias of Network using Link = LinkedTypes and Combine = Union.
  96. template <typename T>
  97. using AllLinksFrom = typename Network<T, LinkedTypes, Union>::type;
  98.  
  99. // Testing
  100. #include <iostream>
  101.  
  102. struct A {};
  103. struct B { using links = std::tuple<A>; };
  104. struct C { using links = std::tuple<A,B>; };
  105. struct D { using links = std::tuple<C>; };
  106. struct E { using links = std::tuple<D>; };
  107. struct F { using links = std::tuple<D>; };
  108. struct G { using links = std::tuple<D>; };
  109. struct H { using links = std::tuple<E,F,G>; };
  110.  
  111. struct Foo;
  112. struct Bar { using links = std::tuple<Foo>; };
  113. struct Foo { using links = std::tuple<Bar>; };
  114.  
  115. int main() {
  116. std::cout << std::boolalpha << std::is_same<
  117. AllLinksFrom<H>,
  118. std::tuple<A,B,C,D,E,F,G,H>
  119. >::value << '\n'; // true
  120.  
  121. // std::cout << std::is_same<
  122. // AllLinksFrom<Foo>,
  123. // std::tuple<Bar, Foo>
  124. // >::value << '\n'; // Infinite recursion.
  125. }
Success #stdin #stdout 0s 3460KB
stdin
Standard input is empty
stdout
true