fork(1) download
  1. #include <array>
  2. #include <cassert>
  3. #include <iostream>
  4. #include <string>
  5. #include <tuple>
  6.  
  7. /**
  8.  * Similar to `optional`, but take the bool as argument.
  9.  */
  10. template <typename T>
  11. class out_optional
  12. {
  13. public:
  14. out_optional() {}
  15.  
  16. out_optional(const out_optional&) = delete;
  17. out_optional& operator =(const out_optional&) = delete;
  18.  
  19. void destruct(bool b) { if (b) { reset(b); } }
  20.  
  21. void reset(bool& b) { if (b) { reinterpret_cast<T*>(data)->~T(); b = false; } }
  22. void reset(bool& b, const T& value) { reset(b); new (data) T{value}; b = true; }
  23. void reset(bool& b, T&& value) { reset(b); new (data) T{value}; b = true; }
  24.  
  25. const T* get_ptr(bool b) const { return b ? reinterpret_cast<T*>(data) : nullptr; }
  26. T* get_ptr(bool b) { return b ? reinterpret_cast<T*>(data) : nullptr; }
  27.  
  28. const T& get(bool b) const { assert(b); return *get_ptr(b); }
  29. T& get(bool b) { assert(b); return *get_ptr(b); }
  30.  
  31. // Other stuff as swap, pseudo assignment/move, more constructors
  32.  
  33. private:
  34. alignas(T) char data[sizeof(T)];
  35. };
  36.  
  37. /**
  38.  * 'Tuple' of optional, packaged with bool at the end.
  39.  */
  40. template <typename ... Ts>
  41. struct multi_optional
  42. {
  43. template <std::size_t I>
  44. using type = typename std::tuple_element<I, std::tuple<Ts...>>::type;
  45.  
  46. static_assert(std::is_same<int, type<0>>::value, "");
  47. public:
  48. multi_optional() = default;
  49.  
  50. ~multi_optional()
  51. {
  52. destruct(std::index_sequence_for<Ts...>());
  53. }
  54.  
  55. multi_optional(const multi_optional&) = delete; // To be implemented.
  56. multi_optional& operator =(const multi_optional&) = delete; // To be implemented.
  57.  
  58. template <std::size_t I>
  59. const auto* get_ptr() const { return std::get<I>(data).get_ptr(flags[I]); }
  60.  
  61. template <std::size_t I>
  62. auto* get_ptr() { return std::get<I>(data).get_ptr(flags[I]); }
  63.  
  64. template <std::size_t I>
  65. const auto& get() const { return std::get<I>(data).get(flags[I]); }
  66.  
  67. template <std::size_t I>
  68. auto& get() { return std::get<I>(data).get(flags[I]); }
  69.  
  70. template <std::size_t I>
  71. void reset() { return std::get<I>(data).reset(flags[I]); }
  72.  
  73. template <std::size_t I>
  74. void reset(const type<I>& value) { return std::get<I>(data).reset(flags[I], value); }
  75.  
  76. private:
  77. template <std::size_t ... Is>
  78. void destruct(std::index_sequence<Is...>)
  79. {
  80. int dummy[] = { 0, (std::get<Is>(data).destruct(flags[Is]), 0)... };
  81. static_cast<void>(dummy);
  82. }
  83.  
  84. private:
  85. std::tuple<out_optional<Ts>...> data;
  86. std::array<bool, sizeof...(Ts)> flags = {{}};
  87. };
  88.  
  89. int main() {
  90. multi_optional<int, std::string> m;
  91.  
  92. assert(m.get_ptr<0>() == nullptr);
  93. assert(m.get_ptr<1>() == nullptr);
  94.  
  95. m.reset<0>(42);
  96. m.reset<1>("hello");
  97.  
  98. std::cout << m.get<1>() << m.get<0>() << std::endl;
  99.  
  100. m.reset<0>();
  101. m.reset<1>();
  102.  
  103. assert(m.get_ptr<0>() == nullptr);
  104. assert(m.get_ptr<1>() == nullptr);
  105. }
  106.  
Success #stdin #stdout 0s 3272KB
stdin
Standard input is empty
stdout
hello42