fork download
  1. #include <iostream>
  2. #include <cstddef>
  3. #include <utility>
  4. #include <cassert>
  5. #include <array>
  6.  
  7. template <typename first, typename ... rest>
  8. struct find_biggest_size
  9. {
  10. constexpr static std::size_t value = (sizeof(first) > find_biggest_size<rest...>::value) ? sizeof(first) : find_biggest_size<rest...>::value;
  11. };
  12.  
  13. template <typename first>
  14. struct find_biggest_size<first>
  15. {
  16. constexpr static std::size_t value = sizeof(first);
  17. };
  18.  
  19. template <typename first, typename second>
  20. struct find_biggest_size<first, second>
  21. {
  22. constexpr static std::size_t value = (sizeof(first) > sizeof(second)) ? sizeof(first) : sizeof(second);
  23. };
  24.  
  25. template <typename type, typename first, typename ... rest>
  26. struct is_present
  27. {
  28. static constexpr bool value = (is_present<type, rest...>::value) ? true : std::is_same<type, first>::value;
  29. static constexpr std::size_t index = is_present<type, rest...>::index + 1;
  30. };
  31.  
  32. template <typename type, typename first>
  33. struct is_present<type, first>
  34. {
  35. static constexpr bool value = std::is_same<type, first>::value;
  36. static constexpr std::size_t index = 0;
  37. };
  38.  
  39. template <std::size_t ind, typename ... Types>
  40. struct extract
  41. {};
  42.  
  43. template <std::size_t ind, typename first, typename ... rest>
  44. struct extract<ind, first, rest...>
  45. {
  46. using type = typename extract<ind - 1, rest...>::type;
  47. };
  48.  
  49. template <typename T>
  50. struct extract<0, T>
  51. {
  52. using type = T;
  53. };
  54.  
  55. template <typename T>
  56. struct in_place_t
  57. {};
  58.  
  59. struct bad_variant_access
  60. {};
  61.  
  62. template <typename ... alternatives>
  63. class variant
  64. {
  65. char object[find_biggest_size<alternatives...>::value];
  66. std::size_t index;
  67. public:
  68. template <typename T>
  69. variant(T&& other)
  70. {
  71. static_assert(is_present<T, alternatives...>::value, "type is not in range");
  72. new ((T*)&object[0]) T(std::forward<T>(other));
  73. index = is_present<T, alternatives...>::index;
  74. }
  75.  
  76. template <typename T>
  77. variant(const T& other)
  78. {
  79. static_assert(is_present<T, alternatives...>::value, "type is not in range");
  80. new ((T*)&object[0]) T(std::forward<T>(other));
  81. index = is_present<T, alternatives...>::index;
  82. }
  83.  
  84. template <typename T, typename ... ArgTypes>
  85. variant(in_place_t<T>, ArgTypes&& ... args)
  86. {
  87. static_assert(is_present<T, alternatives...>::value, "type is not in range");
  88. new ((T*)&object[0]) T(std::forward<ArgTypes>(args)...);
  89. index = is_present<T, alternatives...>::index;
  90. }
  91.  
  92.  
  93.  
  94. template <std::size_t ind, typename ... alts>
  95. friend typename extract<ind, alts...>::type get(variant<alts...>& v)
  96. {
  97. using T = typename extract<ind, alts...>::type;
  98. if (v.index != ind)
  99. {
  100. throw bad_variant_access{};
  101. }
  102.  
  103. return *((T*)(v.object));
  104. }
  105.  
  106. ~variant()
  107. {
  108. static std::array<void(*)(char*), sizeof...(alternatives)> destructors
  109. {
  110. std::addressof(invoke_destructor_impl<alternatives>)...
  111. };
  112. destructors[index](object);
  113. }
  114.  
  115. private:
  116. template<class T> static void invoke_destructor_impl(char* object)
  117. {
  118. auto pt = reinterpret_cast<T*>(object);
  119. pt->~T();
  120. }
  121. };
  122.  
  123. int main() {
  124. variant<int, char, bool> v(true);
  125. std::cout << get<2>(v);
  126.  
  127.  
  128. return 0;
  129. }
Success #stdin #stdout 0s 3468KB
stdin
Standard input is empty
stdout
1