fork(1) download
  1. #include <iostream>
  2. #include <string>
  3. #include <exception>
  4. #include <type_traits>
  5.  
  6. namespace std
  7. {
  8. class bad_optional_access : public std::exception
  9. {
  10. public:
  11. ////////////////////////////////////////////////////////////////////////////////////////////
  12. // Type definition
  13.  
  14. bad_optional_access() = default;
  15. bad_optional_access(const bad_optional_access& that) = default;
  16. virtual ~bad_optional_access() = default;
  17.  
  18. ////////////////////////////////////////////////////////////////////////////////////////////
  19. // Public methods
  20.  
  21. bad_optional_access& operator=(const bad_optional_access& that) = default;
  22. virtual const char* what() const noexcept { return "bad optional access"; };
  23. };
  24.  
  25. template <typename Type>
  26. class optional
  27. {
  28. public:
  29.  
  30. static_assert(!std::is_reference<Type>::value, "Optional type can't be reference");
  31. static_assert(!std::is_array<Type>::value, "Optional type can't be array");
  32.  
  33. ////////////////////////////////////////////////////////////////////////////////////////////
  34. // Type definition
  35.  
  36. using value_type = Type;
  37. template <typename OtherType>
  38. using compatible_t = std::enable_if_t<std::is_constructible<Type, std::remove_cv_t<OtherType>&&>::value, std::remove_cv_t<OtherType>>;
  39.  
  40. ////////////////////////////////////////////////////////////////////////////////////////////
  41. // Construction/destruction
  42.  
  43. optional() = default;
  44.  
  45. optional(const optional& that);
  46. optional(optional&& that) noexcept;
  47.  
  48. template <typename OtherType = Type>
  49. optional(OtherType&& value, std::decay_t<compatible_t<OtherType>>* ptr = nullptr) noexcept;
  50.  
  51. ~optional() noexcept;
  52.  
  53. ////////////////////////////////////////////////////////////////////////////////////////////
  54. // Public methods
  55.  
  56. void swap(optional& that) noexcept;
  57.  
  58. optional& operator=(optional that) noexcept;
  59. template <typename OtherType = Type>
  60. optional& operator=(OtherType&& value) noexcept;
  61.  
  62. const Type* operator->() const;
  63. Type* operator->();
  64. const Type& operator*() const;
  65. Type& operator*();
  66.  
  67. bool has_value() const noexcept;
  68. explicit operator bool() const noexcept;
  69.  
  70. Type& value();
  71. const Type& value() const;
  72.  
  73. template <typename Compatible = Type>
  74. Type value_or(Compatible&& defValue) const;
  75.  
  76. void reset() noexcept;
  77.  
  78. private:
  79.  
  80. ////////////////////////////////////////////////////////////////////////////////////////////
  81. // Data member
  82.  
  83. typename std::aligned_storage<sizeof(Type), __alignof(Type)>::type m_data;
  84. bool m_hasValue = false;
  85. };
  86.  
  87.  
  88.  
  89. ////////////////////////////////////////////////////////////////////////////////////////////////
  90. // Optional comparison operators (declaration)
  91. ////////////////////////////////////////////////////////////////////////////////////////////////
  92.  
  93. template <typename Type>
  94. bool operator==(const optional<Type>& left, const optional<Type>& right);
  95. template <typename Type, typename Compatible>
  96. bool operator==(const optional<Type>& left, const Compatible& right);
  97. template <typename Type, typename Compatible>
  98. bool operator==(const Compatible& left, const optional<Type>& right);
  99.  
  100. template <typename Type>
  101. bool operator!=(const optional<Type>& left, const optional<Type>& right);
  102. template <typename Type, typename Compatible>
  103. bool operator!=(const optional<Type>& left, const Compatible& right);
  104. template <typename Type, typename Compatible>
  105. bool operator!=(const Compatible& left, const optional<Type>& right);
  106.  
  107. template <typename Type>
  108. bool operator<(const optional<Type>& left, const optional<Type>& right);
  109. template <typename Type, typename Compatible>
  110. bool operator<(const optional<Type>& left, const Compatible& right);
  111. template <typename Type, typename Compatible>
  112. bool operator<(const Compatible& left, const optional<Type>& right);
  113.  
  114. template <typename Type>
  115. bool operator>(const optional<Type>& left, const optional<Type>& right);
  116. template <typename Type, typename Compatible>
  117. bool operator>(const optional<Type>& left, const Compatible& right);
  118. template <typename Type, typename Compatible>
  119. bool operator>(const Compatible& left, const optional<Type>& right);
  120.  
  121.  
  122.  
  123. ////////////////////////////////////////////////////////////////////////////////////////////////
  124. // class optional (implementation)
  125. ////////////////////////////////////////////////////////////////////////////////////////////////
  126.  
  127. ////////////////////////////////////////////////////////////////////////////////////////////////
  128. // Construction/destruction
  129.  
  130. template <typename Type>
  131. inline optional<Type>::optional(const optional& that)
  132. {
  133. if (that.has_value())
  134. new(this) optional(*that);
  135. }
  136.  
  137.  
  138.  
  139. ////////////////////////////////////////////////////////////////////////////////////////////////
  140. template <typename Type>
  141. inline optional<Type>::optional(optional&& that) noexcept
  142. {
  143. if (that.has_value()) {
  144.  
  145. new(this) optional(std::move(*that));
  146. that.~optional();
  147. }
  148. }
  149.  
  150.  
  151.  
  152. ////////////////////////////////////////////////////////////////////////////////////////////////
  153. template <typename Type>
  154. template <typename OtherType>
  155. inline optional<Type>::optional(OtherType&& value, std::decay_t<compatible_t<OtherType>>*) noexcept
  156. {
  157. new(&m_data) Type(std::forward<OtherType>(value));
  158. m_hasValue = true;
  159. }
  160.  
  161.  
  162.  
  163. ////////////////////////////////////////////////////////////////////////////////////////////////
  164. template <typename Type>
  165. inline optional<Type>::~optional() noexcept
  166. {
  167. if (has_value()) {
  168.  
  169. reinterpret_cast<Type&>(m_data).~Type();
  170. m_hasValue = false;
  171. }
  172. }
  173.  
  174.  
  175.  
  176. ////////////////////////////////////////////////////////////////////////////////////////////////
  177. // Public methods
  178.  
  179. ////////////////////////////////////////////////////////////////////////////////////////////////
  180. template <typename Type>
  181. inline void optional<Type>::swap(optional& that) noexcept
  182. {
  183. using std::swap;
  184.  
  185. if (has_value() && that.has_value())
  186. swap(*(*this), *that);
  187. else if (has_value() && !that.has_value())
  188. new(&that) optional(std::move(*this));
  189. else if (!has_value() && that.has_value())
  190. new(this) optional(std::move(that));
  191. }
  192.  
  193.  
  194.  
  195. ////////////////////////////////////////////////////////////////////////////////////////////////
  196. template <typename Type>
  197. inline optional<Type>& optional<Type>::operator=(optional that) noexcept
  198. {
  199. swap(that);
  200.  
  201. return *this;
  202. }
  203.  
  204.  
  205.  
  206. ////////////////////////////////////////////////////////////////////////////////////////////////
  207. template <typename Type>
  208. template <typename OtherType>
  209. inline optional<Type>& optional<Type>::operator=(OtherType&& value) noexcept
  210. {
  211. optional(std::move(value)).swap(*this);
  212.  
  213. return *this;
  214. }
  215.  
  216.  
  217.  
  218. ////////////////////////////////////////////////////////////////////////////////////////////////
  219. template <typename Type>
  220. inline const Type* optional<Type>::operator->() const
  221. {
  222. return reinterpret_cast<const Type*>(&m_data);
  223. }
  224.  
  225.  
  226.  
  227. ////////////////////////////////////////////////////////////////////////////////////////////////
  228. template <typename Type>
  229. inline Type* optional<Type>::operator->()
  230. {
  231. return reinterpret_cast<Type*>(&m_data);
  232. }
  233.  
  234.  
  235.  
  236. ////////////////////////////////////////////////////////////////////////////////////////////////
  237. template <typename Type>
  238. inline const Type& optional<Type>::operator*() const
  239. {
  240. return reinterpret_cast<const Type&>(m_data);
  241. }
  242.  
  243.  
  244.  
  245. ////////////////////////////////////////////////////////////////////////////////////////////////
  246. template <typename Type>
  247. inline Type& optional<Type>::operator*()
  248. {
  249. return reinterpret_cast<Type&>(m_data);
  250. }
  251.  
  252.  
  253.  
  254. ////////////////////////////////////////////////////////////////////////////////////////////////
  255. template <typename Type>
  256. inline bool optional<Type>::has_value() const noexcept
  257. {
  258. return m_hasValue;
  259. }
  260.  
  261.  
  262.  
  263. ////////////////////////////////////////////////////////////////////////////////////////////////
  264. template <typename Type>
  265. inline optional<Type>::operator bool() const noexcept
  266. {
  267. return has_value();
  268. }
  269.  
  270.  
  271.  
  272. ////////////////////////////////////////////////////////////////////////////////////////////////
  273. template <typename Type>
  274. inline Type& optional<Type>::value()
  275. {
  276. if (!has_value())
  277. throw bad_optional_access();
  278.  
  279. return *(*this);
  280. }
  281.  
  282.  
  283.  
  284. ////////////////////////////////////////////////////////////////////////////////////////////////
  285. template <typename Type>
  286. inline const Type& optional<Type>::value() const
  287. {
  288. if (!has_value())
  289. throw bad_optional_access();
  290.  
  291. return *(*this);
  292. }
  293.  
  294.  
  295.  
  296. ////////////////////////////////////////////////////////////////////////////////////////////////
  297. template <typename Type>
  298. template <typename Compatible>
  299. inline Type optional<Type>::value_or(Compatible&& defValue) const
  300. {
  301. if (!has_value())
  302. return static_cast<Type>(std::forward<Compatible>(defValue));
  303.  
  304. return *(*this);
  305. }
  306.  
  307.  
  308.  
  309. ////////////////////////////////////////////////////////////////////////////////////////////////
  310. template <typename Type>
  311. inline void optional<Type>::reset() noexcept
  312. {
  313. optional().swap(*this);
  314. }
  315.  
  316.  
  317.  
  318. ////////////////////////////////////////////////////////////////////////////////////////////////
  319. // Optional comparison operators (implementation)
  320. ////////////////////////////////////////////////////////////////////////////////////////////////
  321.  
  322. ////////////////////////////////////////////////////////////////////////////////////////////////
  323. template <typename Type>
  324. inline bool operator==(const optional<Type>& left, const optional<Type>& right)
  325. {
  326. if (left.has_value() != right.has_value())
  327. return false;
  328.  
  329. if (!left.has_value())
  330. return true;
  331.  
  332. return *left == *right;
  333. }
  334.  
  335.  
  336.  
  337. ////////////////////////////////////////////////////////////////////////////////////////////////
  338. template <typename Type, typename Compatible>
  339. inline bool operator==(const optional<Type>& left, const Compatible& right)
  340. {
  341. if (!left.has_value())
  342. return false;
  343.  
  344. return *left == right;
  345. }
  346.  
  347.  
  348.  
  349. ////////////////////////////////////////////////////////////////////////////////////////////////
  350. template <typename Type, typename Compatible>
  351. inline bool operator==(const Compatible& left, const optional<Type>& right)
  352. {
  353. if (!right.has_value())
  354. return false;
  355.  
  356. return left == *right;
  357. }
  358.  
  359.  
  360.  
  361. ////////////////////////////////////////////////////////////////////////////////////////////////
  362. template <typename Type>
  363. inline bool operator!=(const optional<Type>& left, const optional<Type>& right)
  364. {
  365. return !operator==(left, right);
  366. }
  367.  
  368.  
  369.  
  370. ////////////////////////////////////////////////////////////////////////////////////////////////
  371. template <typename Type, typename Compatible>
  372. inline bool operator!=(const optional<Type>& left, const Compatible& right)
  373. {
  374. return !operator==(left, right);
  375. }
  376.  
  377.  
  378.  
  379. ////////////////////////////////////////////////////////////////////////////////////////////////
  380. template <typename Type, typename Compatible>
  381. inline bool operator!=(const Compatible& left, const optional<Type>& right)
  382. {
  383. return !operator==(left, right);
  384. }
  385.  
  386.  
  387.  
  388. ////////////////////////////////////////////////////////////////////////////////////////////////
  389. template <typename Type>
  390. inline bool operator<(const optional<Type>& left, const optional<Type>& right)
  391. {
  392. if (left.has_value() && !right.has_value())
  393. return false;
  394.  
  395. if (!left.has_value() && right.has_value())
  396. return true;
  397.  
  398. if (left.has_value())
  399. return *left < *right;
  400.  
  401. return false;
  402. }
  403.  
  404.  
  405.  
  406. ////////////////////////////////////////////////////////////////////////////////////////////////
  407. template <typename Type, typename Compatible>
  408. inline bool operator<(const optional<Type>& left, const Compatible& right)
  409. {
  410. if (!left.has_value())
  411. return true;
  412.  
  413. return *left < right;
  414. }
  415.  
  416.  
  417.  
  418. ////////////////////////////////////////////////////////////////////////////////////////////////
  419. template <typename Type, typename Compatible>
  420. inline bool operator<(const Compatible& left, const optional<Type>& right)
  421. {
  422. if (!right.has_value())
  423. return false;
  424.  
  425. return left < *right;
  426. }
  427.  
  428.  
  429.  
  430. ////////////////////////////////////////////////////////////////////////////////////////////////
  431. template <typename Type>
  432. inline bool operator>(const optional<Type>& left, const optional<Type>& right)
  433. {
  434. return right < left;
  435. }
  436.  
  437.  
  438.  
  439. ////////////////////////////////////////////////////////////////////////////////////////////////
  440. template <typename Type, typename Compatible>
  441. inline bool operator>(const optional<Type>& left, const Compatible& right)
  442. {
  443. return right < left;
  444. }
  445.  
  446.  
  447.  
  448. ////////////////////////////////////////////////////////////////////////////////////////////////
  449. template <typename Type, typename Compatible>
  450. inline bool operator>(const Compatible& left, const optional<Type>& right)
  451. {
  452. return right < left;
  453. }
  454.  
  455. } // namespace std
  456.  
  457. struct SomeClass {};
  458.  
  459. struct Container
  460. {
  461. Container() = default;
  462. explicit Container(int) {}
  463. explicit Container(double) {}
  464. explicit Container(const std::string&) {}
  465. explicit Container(const SomeClass&) {}
  466. explicit Container(const std::optional<SomeClass>&) {}
  467.  
  468. explicit operator int () const {return {}; }
  469. explicit operator double () const {return {}; }
  470. explicit operator std::string () const {return {}; }
  471. explicit operator SomeClass () const {return {}; }
  472. explicit operator std::optional<SomeClass> () const {return {}; }
  473. };
  474.  
  475. ////////////////////////////////////////////////////////////////////////////////
  476. // Test
  477. ////////////////////////////////////////////////////////////////////////////////
  478.  
  479. const Container cont1(int{});
  480. const Container cont2(double{});
  481. const Container cont3(std::string{});
  482. const Container cont4(SomeClass{});
  483. const Container cont5(std::optional<SomeClass>{});
  484.  
  485. const double v1(cont1);
  486. const int v2(cont2);
  487. const std::string v3(cont3);
  488. const SomeClass v4(cont4);
  489. const std::optional<int> v5(cont5);
  490.  
  491. int main() {
  492.  
  493. std::optional<int> opt = 1234;
  494. std::optional<int> optCopy;
  495.  
  496. optCopy = opt;
  497.  
  498. std::cout << optCopy.value();
  499. }
Success #stdin #stdout 0s 15232KB
stdin
Standard input is empty
stdout
1234