Utility.Either.tlh 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. //-----------------------------------------------------------------------------
  2. //-----------------------------------------------------------------------------
  3. #pragma once
  4. #include <type_traits>
  5. #include <optional>
  6. #include <variant>
  7. //-----------------------------------------------------------------------------
  8. // Either
  9. // 测试发现, 如果 R 是一个对象, 而且整个使用过程中一直没有引用 R,
  10. // 那么 R 永远不会被构造
  11. // 见文末的测试
  12. //
  13. // 因此, 可以放心地当成 std::expect <T, E> 来使用
  14. // 因为正常情况下, 是不会有 E 的.
  15. //
  16. // std::optional <T> 也是如此, 如果返回 nullopt, 那么 T 不会被构造
  17. // 为避免 L 与 R 相同时造成编译错误, 用以下语句来禁用一部分成员函数:
  18. // template <typename Dummy = void, typename = std::enable_if <! std::is_same <TL, TR>::value, Dummy>::type>
  19. // 或者写成
  20. // template <typename Dummy = void, typename = std::enable_if_t <! std::is_same <TL, TR>::value>>
  21. // 这两种语法都是合法的
  22. //
  23. //-----------------------------------------------------------------------------
  24. namespace ECOM::Utility
  25. {
  26. template <typename TL>
  27. struct __tLeft
  28. {
  29. TL value;
  30. };
  31. template <typename TR>
  32. struct __tRight
  33. {
  34. TR value;
  35. };
  36. // 从 value 构造出 Left/Right 类型
  37. template <typename TL>
  38. constexpr __tLeft <TL> left (const TL & _value) { return { _value }; }
  39. template <typename TR>
  40. constexpr __tRight <TR> right (const TR & _value) { return { _value }; }
  41. template <typename TL>
  42. constexpr __tLeft <TL> left (TL && _value) { return { std::move (_value) }; }
  43. template <typename TR>
  44. constexpr __tRight <TR> right (TR && _value) { return { std::move (_value) }; }
  45. template <typename TL, typename TR>
  46. struct Either
  47. {
  48. template <typename> static constexpr bool dependent_false = false;
  49. public:
  50. using type_left = typename TL;
  51. using type_right = typename TR;
  52. private:
  53. std::variant < TL, TR > value;
  54. public:
  55. constexpr Either () = delete; // ! 不支持默认构造函数, 否则没法知道是左还是右 !
  56. //< 拷贝构造函数及移动构造函数
  57. constexpr Either (Either <TL, TR> const & e) : value { e.value } {}
  58. constexpr Either (Either <TL, TR> && e) : value { std::move (e.value) } {}
  59. //>
  60. //< 从 left 或 right 构造
  61. constexpr Either (__tLeft <TL> const & _left) : value { _left.value } {}
  62. constexpr Either (__tRight <TR> const & _right) : value { _right.value } {}
  63. constexpr Either (__tLeft <TL> && _left) : value { std::move (_left.value) } {}
  64. constexpr Either (__tRight <TR> && _right) : value { std::move (_right.value) } {}
  65. //>
  66. //< 直接从 value 构造
  67. // 但是只构造 left, 不构造 right;
  68. // 原因是, 调用者很难意识到: 是构造了 left, 还是构造了 right ?
  69. explicit constexpr Either (TL const & _left) : value { _left} {}
  70. explicit constexpr Either (TL && _left) : value { std::move (_left) } {}
  71. template <typename Dummy = void, typename = std::enable_if_t <! std::is_same <TL, TR>::value>>
  72. constexpr Either (TR const & _right) : value { _right } {}
  73. template <typename Dummy = void, typename = std::enable_if_t <! std::is_same <TL, TR>::value>>
  74. constexpr Either (TR && _right) : value { std::move (_right) } {}
  75. //>
  76. // 析构函数
  77. ~Either () = default;
  78. public: // 赋值. ?? 只赋值一侧, 赋值后, 要清除另一侧吗 ??
  79. constexpr Either & operator = (Either <TL, TR> const & from)
  80. {
  81. value = from.value;
  82. return (*this);
  83. }
  84. constexpr Either & operator = (Either <TL, TR> && from)
  85. {
  86. value = std::move (from.value);
  87. return (*this);
  88. }
  89. constexpr Either & operator = (TL const & _left)
  90. {
  91. value = _left;
  92. return (*this);
  93. }
  94. constexpr Either & operator = (TL && _left)
  95. {
  96. value = std::move (_left);
  97. return (*this);
  98. }
  99. template <typename Dummy = void, typename = std::enable_if_t <! std::is_same <TL, TR>::value>>
  100. constexpr Either & operator = (TR const & _right)
  101. {
  102. value = _right;
  103. return (*this);
  104. }
  105. template <typename Dummy = void, typename = std::enable_if_t <! std::is_same <TL, TR>::value>>
  106. constexpr Either & operator = (TR && _right)
  107. {
  108. value = std::move (_right);
  109. return (*this);
  110. }
  111. constexpr bool operator == (const Either <TL, TR> & _with) const { return value == _with.value; }
  112. constexpr bool operator != (const Either <TL, TR> & _with) const { return value != _with.value; }
  113. constexpr bool operator < (const Either <TL, TR> & _with) const { return value < _with.value; }
  114. constexpr bool operator > (const Either <TL, TR> & _with) const { return value > _with.value; }
  115. constexpr bool operator <= (const Either <TL, TR> & _with) const { return value <= _with.value; }
  116. constexpr bool operator >= (const Either <TL, TR> & _with) const { return value >= _with.value; }
  117. public:
  118. constexpr bool isLeft () const
  119. {
  120. return value.index () == 0;
  121. }
  122. constexpr bool isRight () const
  123. {
  124. return value.index () == 1;
  125. }
  126. constexpr operator bool () const
  127. {
  128. return value.index () == 0;
  129. }
  130. public:
  131. //< 禁止自动转换, 免得误转换了都不知道
  132. constexpr operator TL () const = delete;
  133. template <typename Dummy = void, typename = std::enable_if_t <! std::is_same <TL, TR>::value>>
  134. constexpr operator TR () const = delete;
  135. //>
  136. public:
  137. //< 基于类型的判断和转换
  138. // using dwString = ECOM::Utility::Either <eSTR::DString, eSTR::WString>;
  139. // auto b1 = dwAck.is <eSTR::DString> ();
  140. // auto b2 = dwAck.is <eSTR::WString> ();
  141. // const auto v1 = dwAck.get <eSTR::DString> ();
  142. // const auto v2 = dwAck.get <eSTR::WString> ();
  143. template <typename T>
  144. constexpr bool is () const
  145. {
  146. static_assert (dependent_false <T>, "only support <TL> or <TR>");
  147. }
  148. template <> constexpr bool is <TL> () const { return value.index () == 0; }
  149. template <> constexpr bool is <TR> () const { return value.index () == 1; }
  150. template <typename T> constexpr const T & get () const
  151. {
  152. static_assert (dependent_false <T>, "only support <TL> or <TR>");
  153. }
  154. template <> constexpr const TL & get <TL> () const { return getLeft (); }
  155. template <> constexpr const TR & get <TR> () const { return getRight (); }
  156. template <typename T> constexpr const T * get_if () const
  157. {
  158. static_assert (dependent_false <T>, "only support <TL> or <TR>");
  159. }
  160. template <> constexpr const TL * get_if <TL> () const { return getIfLeft (); }
  161. template <> constexpr const TR * get_if <TR> () const { return getIfRight (); }
  162. //>
  163. public:
  164. //< 基于整数的判断和转换. 例子代码如下:
  165. // using dwString = ECOM::Utility::Either <eSTR::DString, eSTR::WString>;
  166. // auto b0 = dwAck.is <0> ();
  167. // auto b1 = dwAck.is <1> ();
  168. // const auto v0 = dwAck.get <0> ();
  169. // const auto v1 = dwAck.get <1> ();
  170. // eSTR::DString s0; eSTR::WString s1;
  171. // b0 = dwAck.to (s0);
  172. // b1 = dwAck.to (s1);
  173. template <int k, typename = std::enable_if_t < k==0 || k == 1 >>
  174. constexpr bool is () const
  175. {
  176. return (value.index () == k);
  177. }
  178. template <int k, typename = std::enable_if_t < k == 0>>
  179. constexpr const TL & get () const { return getLeft (); }
  180. template <int k, typename = std::enable_if_t < k == 1 >>
  181. constexpr const TR & get () const { return getRight (); }
  182. template <int k, typename = std::enable_if_t < k == 0>>
  183. constexpr TL & get () { return getLeft (); }
  184. template <int k, typename = std::enable_if_t < k == 1 >>
  185. constexpr TR & get () { return getRight (); }
  186. // 如下写法, 语法上没问题, 但是容易导致编译器混淆如下两条语句:
  187. // ei.get <0> ()
  188. // ei.get <false> ();
  189. // 糟糕的是, 这两条语句的语义还是相反的
  190. // template <bool k, typename = std::enable_if_t < k == true>>
  191. // constexpr TL & get () { return getLeft (); }
  192. // template <bool k, typename = std::enable_if_t < k == false >>
  193. // constexpr TR & get () { return getRight (); }
  194. template <int k, typename = std::enable_if_t < k == 0>>
  195. constexpr const TL * get_if () const { return getIfLeft (); }
  196. template <int k, typename = std::enable_if_t < k == 1 >>
  197. constexpr const TR * get_if () const { return getIfRight (); }
  198. template <int k, typename = std::enable_if_t < k == 0>>
  199. constexpr TL * get_if () { return getIfLeft (); }
  200. template <int k, typename = std::enable_if_t < k == 1 >>
  201. constexpr TR * get_if () { return getIfRight (); }
  202. public:
  203. //<
  204. template <typename T>
  205. constexpr bool onLeftTo (T & _val)
  206. {
  207. if (value.index () == 0)
  208. {
  209. _val = std::get <TL> (value);
  210. return true;
  211. }
  212. return false;
  213. }
  214. template <typename T>
  215. constexpr bool onRightTo (T & _val)
  216. {
  217. if (value.index () == 1)
  218. {
  219. _val = std::get <TR> (value);
  220. return true;
  221. }
  222. return false;
  223. }
  224. //>
  225. //< 两个 to 函数, 不需要事先判断. 如果可以, 就赋值给传入的参数. 返回: 是否赋值
  226. constexpr bool to (TL & _val)
  227. {
  228. if (value.index () == 0)
  229. {
  230. _val = std::get <TL> (value);
  231. return true;
  232. }
  233. return false;
  234. }
  235. constexpr bool to (TR & _val)
  236. {
  237. if (value.index () == 1)
  238. {
  239. _val = std::get <TR> (value);
  240. return true;
  241. }
  242. return false;
  243. }
  244. //>
  245. public:
  246. //< 作为左侧或右侧返回其引用. 如果不匹配, std::get <> 扔一个例外 : std::bad_variant_access
  247. constexpr const TL & getLeft () const { return std::get <TL> (value); }
  248. constexpr const TR & getRight () const { return std::get <TR> (value); }
  249. constexpr TL & getLeft () { return std::get <TL> (value); }
  250. constexpr TR & getRight () { return std::get <TR> (value); }
  251. //>
  252. //< 作为左侧或右侧返回其指针. 如果不匹配, 返回 nullptr
  253. constexpr const TL * getIfLeft () const { return std::get_if <TL> (value); }
  254. constexpr const TR * getIfRight () const { return std::get_if <TR> (value); }
  255. constexpr TL * getIfLeft () { return std::get_if <TL> (value); }
  256. constexpr TR * getIfRight () { return std::get_if <TR> (value); }
  257. //>
  258. public:
  259. // 如果是 Left, 就执行指定的函数, 参数就是 leftValue
  260. template <typename F, typename ... Args>
  261. constexpr Either & onLeft (F && f, Args && ... args)
  262. {
  263. if (isLeft ())
  264. f (getLeft (), std::forward <Args> (args)...);
  265. return (*this);
  266. }
  267. // 如果是 right, 就执行指定的函数, 参数就是 rightValue
  268. template <typename F, typename ... Args>
  269. constexpr Either & onRight (F && f, Args && ... args)
  270. {
  271. if (isRight ())
  272. f (getRight (), std::forward <Args> (args)...);
  273. return (*this);
  274. }
  275. //>
  276. //< 映射
  277. // 把我的 TL 作为参数, 施加于 F 函数, 最终映射成另外一个 either
  278. // 如果是左侧, 就用左侧传入给定的函数, 返回值也作为左侧
  279. // 如果是右侧, 直接返回
  280. // F 的返回值类型是 U, map () 的返回值类型是 Either <U, TR>
  281. // 某些语言把类似功能定义为 transform 函数
  282. template <typename F, typename ... Args>
  283. constexpr auto map (F && f, Args && ... args) const & -> Either <typename std::invoke_result_t <F, TL &, Args && ...>, TR>
  284. {
  285. if (isLeft ())
  286. return { left (f (std::get <TL> (value), std::forward <Args> (args)...)) };
  287. return { right (std::get <TR> (value)) };
  288. }
  289. template <typename F, typename ... Args>
  290. constexpr auto map (F && f, Args && ... args) && -> Either <typename std::invoke_result_t <F, TL &&, Args && ...>, TR>
  291. {
  292. if (isLeft ())
  293. return { left (f (std::move (std::get <TL> (value)), std::forward <Args> (args)...)) };
  294. return { right (std::move (std::get <TR> (value))) };
  295. }
  296. //>
  297. //< 带默认值的映射
  298. //< 把我的 TL 作为参数, 作用到 F 函数上
  299. // 如果是左侧, 就用左侧传入给定的函数, 然后返回 F 的返回值
  300. // 如果是右侧, 返回默认值
  301. // F 的返回值类型是 U, map_or () 的返回值类型也是 U
  302. template <typename U, typename F, typename ... Args>
  303. constexpr auto map_or (const U & u, F && f, Args && ... args) const & -> U
  304. {
  305. if (isLeft ())
  306. return f (std::get <TL> (value), std::forward <Args> (args)...);
  307. return (u);
  308. }
  309. template <typename U, typename F, typename ... Args>
  310. constexpr auto map_or (U && u, F && f, Args && ... args) && -> U
  311. {
  312. if (isLeft ())
  313. return f (std::move (std::get <TL> (value)), std::forward <Args> (args)...);
  314. return std::move (u);
  315. }
  316. //>
  317. //< 把我的 TL 作为参数, 调用 F 函数, 结果变成另外一个 either
  318. // 如果是左侧, 就用左侧传入给定的函数, 返回值也作为左侧
  319. // 如果是右侧, 直接返回
  320. // F 的返回值类型是 Either <U, TR>, 也就是说, 左值的类型可以变, 但是右值的类型不能变
  321. // 比如 this 的类型是 <int, string>, F 可以返回类型 <double, string>, 但是不能返回类型 <double, bool>
  322. // 某些语言把类似功能定义为 flatMap 函数
  323. template <typename F, typename ... Args>
  324. constexpr auto and_then (F && f, Args && ... args) const & -> typename std::invoke_result_t <F, TL &, Args && ...>
  325. {
  326. if (isLeft ())
  327. return { f (std::get <TL> (value), std::forward <Args> (args)...) };
  328. return { right (std::get <TR> (value)) };
  329. }
  330. template <typename F, typename ... Args>
  331. constexpr auto and_then (F && f, Args && ... args) && -> typename std::invoke_result_t <F, TL &, Args && ...>
  332. {
  333. if (isLeft ())
  334. return { f (std::move (std::get <TL> (value)), std::forward <Args> (args)...) };
  335. return { right (std::move (std::get <TR> (value))) };
  336. }
  337. //>
  338. //< 把我的 TR 作为参数, 调用 F 函数, 结果变成另外一个 either
  339. // 如果是右侧, 就用左侧传入给定的函数, 返回值也作为左侧
  340. // 如果是左侧, 直接返回
  341. // F 的返回值类型是 Either <TL, U>, 也就是说, 左值的类型不能变, 但是右值的类型可以变
  342. // 比如 this 的类型是 <int, string>, F 可以返回类型 <int, bool>, 但是不能返回类型 <double, bool>
  343. template <typename F, typename ... Args>
  344. constexpr auto or_else (F && f, Args && ... args) const & -> typename std::invoke_result_t <F, TR &, Args && ...>
  345. {
  346. if (isRight ())
  347. return { f (std::get <TR> (value), std::forward <Args> (args)...) };
  348. return { left (std::get <TL> (value)) };
  349. }
  350. template <typename F, typename ... Args>
  351. constexpr auto or_else (F && f, Args && ... args) && -> typename std::invoke_result_t <F, TR &, Args && ...>
  352. {
  353. if (isRight ())
  354. return { f (std::move (std::get <TR> (value)), std::forward <Args> (args)...) };
  355. return { left (std::move (std::get <TL> (value))) };
  356. }
  357. //>
  358. #if 0 // 编译出错: 函数重定义, 暂时禁用此功能
  359. //<
  360. // 把 Either <A, Either <A, B> > 变换成 Either <A, B>
  361. // 注意 共有类型 A
  362. // 比如把 Either <int, Either <int, string> > 变换成 Either <int, string>
  363. // template <typename Either <TL, typename TR::type_right>, typename = std::enable_if_t <std::is_same <TL, TR::type_left>::value>>
  364. template <typename = std::enable_if_t <std::is_same <TL, TR::type_left>::value>>
  365. constexpr auto flatten ()
  366. {
  367. if (isLeft ())
  368. return Either <TL, TR::type_right> { getLeft () };
  369. return getRight ();
  370. }
  371. //>
  372. //<
  373. // 把 Either < <Either <A, B>, B> > 变换成 Either <A, B>
  374. // 注意 共有类型 B
  375. // 比如把 Either < Either <int, string>, string> 变换成 Either <int, string>
  376. template <typename Dummy = void, typename = std::enable_if_t <std::is_same <TL::type_right, TR>::value>>
  377. constexpr auto flatten ()
  378. {
  379. if (isLeft ())
  380. return getLeft ();
  381. return Either <TL::type_left, TR> { getRight () };
  382. }
  383. //>
  384. #endif
  385. #if 1 // 改成这种方式, 就不会导致编译错误了. 这两个函数的签名似乎不同
  386. //<
  387. // 把 Either <A, Either <A, B> > 变换成 Either <A, B>
  388. // 注意 共有类型 A
  389. // 比如把 Either <int, Either <int, string> > 变换成 Either <int, string>
  390. template <typename = std::enable_if_t <std::is_same <TL, TR::type_left>::value>>
  391. constexpr auto flatten ()
  392. {
  393. if (isLeft ())
  394. return Either <TL, TR::type_right> { getLeft () };
  395. return getRight ();
  396. }
  397. //>
  398. //<
  399. // 把 Either < <Either <A, B>, B> > 变换成 Either <A, B>
  400. // 注意 共有类型 B
  401. // 比如把 Either < Either <int, string>, string> 变换成 Either <int, string>
  402. template <typename Dummy = void, typename = std::enable_if_t <std::is_same <TL::type_right, TR>::value>>
  403. constexpr auto flatten ()
  404. {
  405. if (isLeft ())
  406. return getLeft ();
  407. return Either <TL::type_left, TR> { getRight () };
  408. }
  409. //>
  410. #endif
  411. template <typename LL = TL, typename RR = TR>
  412. constexpr auto join () const -> typename std::common_type <LL, RR>::type
  413. {
  414. using toType = typename std::common_type <LL, RR>::type;
  415. if (isLeft ())
  416. return static_cast <toType> (std::get <0> (value));
  417. else
  418. return static_cast <toType> (std::get <1> (value));
  419. }
  420. public:
  421. constexpr static Either make (TL const & _left) { return Either { _left }; }
  422. constexpr static Either make (TL && _left) { return Either { std::move (_left) }; }
  423. template <typename Dummy = void, typename = std::enable_if_t <! std::is_same <TL, TR>::value>>
  424. constexpr static Either make (TR const & _right)
  425. {
  426. return Either { _right };
  427. }
  428. template <typename Dummy = void, typename = std::enable_if_t <! std::is_same <TL, TR>::value>>
  429. constexpr static Either make (TR && _right)
  430. {
  431. return Either {std::move (_right) };
  432. }
  433. template <typename tAny>
  434. constexpr static Either from (Either <TL, tAny> && ei)
  435. {
  436. assert (ei.isLeft ());
  437. return Either { std::move (ei.getLeft ()) };
  438. }
  439. template <typename tAny>
  440. constexpr static Either from (Either <tAny, TR> && ei)
  441. {
  442. assert (ei.isRight ());
  443. return Either { std::move (ei.getRight ()) };
  444. }
  445. }; // class Either
  446. template <typename TL, typename tAny>
  447. constexpr __tLeft <TL> left (Either <TL, tAny> && ei)
  448. {
  449. assert (ei.isLeft ());
  450. return { std::move (ei.getLeft ()) };
  451. }
  452. template <typename tAny, typename TR>
  453. constexpr __tRight <TR> right (Either <tAny, TR> && ei)
  454. {
  455. assert (ei.isRight ());
  456. return { std::move (ei.getRight ()) };
  457. }
  458. }
  459. /*//-----------------------------------------------------------------------------
  460. // 1. 如下语句, 编译通过且能运行
  461. class XString
  462. {
  463. private:
  464. XString ();
  465. };
  466. void Test ()
  467. {
  468. using eiResult = ::Utility::Either <int, XString>;
  469. eiResult x { ::Utility::left (2) };
  470. auto y = std::move (x);
  471. int a = y.asLeft ();
  472. }
  473. // 2. 两个 Either 类型, 但是 TL 或 TR 相同, 可以用如下语句来转换
  474. 但是使用之前必须先判断类型
  475. return eiResult { std::move (eiBLOBAck.getRight ()) };
  476. // return eiResult { std::move (eiBLOBAck.get <1> ()) };
  477. // return std::move (eiBLOBAck.getRight ());
  478. *///-----------------------------------------------------------------------------