fork(1) download
  1. #include <iostream>
  2. #include <typeinfo>
  3. #include <type_traits>
  4.  
  5. struct Grandma {};
  6. struct Mom: Grandma {};
  7. struct Daughter: Mom {};
  8. struct Son: Mom {};
  9. struct Grandchild: Son {};
  10.  
  11. struct Stranger {};
  12.  
  13. namespace detail
  14. {
  15.  
  16. struct TypeIsNotPartOfTheHierarchy {};
  17.  
  18. template<typename T>
  19. struct TypeWrapper
  20. {
  21. static_assert(!std::is_same<TypeIsNotPartOfTheHierarchy, T>::value,
  22. "using types of different type hierarchies.");
  23.  
  24. using type = T;
  25. };
  26.  
  27. template<typename StillCommonAncestor, typename TypeToCheck, typename... Ts>
  28. struct IsCommonAncestor;
  29.  
  30. template<typename StillCommonAncestor, typename TypeToCheck>
  31. struct IsCommonAncestor<StillCommonAncestor, TypeToCheck>
  32. {
  33. static constexpr bool value = StillCommonAncestor::value;
  34. };
  35.  
  36. template<typename StillCommonAncestor, typename TypeToCheck, typename T1, typename... Ts>
  37. struct IsCommonAncestor<StillCommonAncestor, TypeToCheck, T1, Ts...>:
  38. IsCommonAncestor
  39. <
  40. std::integral_constant
  41. <
  42. bool,
  43. std::conditional
  44. <
  45. std::is_base_of<TypeToCheck, T1>::value,
  46. std::true_type,
  47. std::false_type
  48. >::type::value && StillCommonAncestor::value
  49. >,
  50. TypeToCheck,
  51. Ts...
  52. >
  53. {};
  54.  
  55. template<typename Pack, typename... Ts>
  56. struct LCA;
  57.  
  58. template<typename... PackParams, typename T1>
  59. struct LCA<std::tuple<PackParams...>, T1>:
  60. std::conditional
  61. <
  62. IsCommonAncestor<std::true_type, T1, PackParams...>::value,
  63. TypeWrapper<T1>,
  64. TypeWrapper<TypeIsNotPartOfTheHierarchy>
  65. >::type
  66. {};
  67.  
  68. template<typename... PackParams, typename T1, typename... Ts>
  69. struct LCA<std::tuple<PackParams...>, T1, Ts...>:
  70. std::conditional
  71. <
  72. IsCommonAncestor<std::true_type, T1, PackParams...>::value,
  73. TypeWrapper<T1>,
  74. LCA<std::tuple<PackParams...>, Ts...>
  75. >::type
  76. {};
  77.  
  78. }
  79.  
  80. template<typename... Ts>
  81. struct LCA: detail::LCA<std::tuple<Ts...>, Ts...>
  82. {};
  83.  
  84. int main()
  85. {
  86. std::cout << typeid(LCA<Son, Daughter, Mom, Grandchild, Grandma, Son, Son>::type).name() << std::endl;
  87. std::cout << typeid(LCA<Son>::type).name() << std::endl;
  88. std::cout << typeid(LCA<Grandma, Daughter, Son>::type).name() << std::endl;
  89.  
  90. // error because Daughter and Son are orphans in the list
  91. // std::cout << typeid(LCA<Daughter, Son>::type).name() << std::endl;
  92.  
  93. // error because the Son and his Grandma are not related to Stranger.
  94. // std::cout << typeid(LCA<Grandma, Stranger, Son>::type).name() << std::endl;
  95.  
  96. return 0;
  97. }
Success #stdin #stdout 0s 3340KB
stdin
Standard input is empty
stdout
7Grandma
3Son
7Grandma