//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- #pragma once #include #include #include //----------------------------------------------------------------------------- // Either // 测试发现, 如果 R 是一个对象, 而且整个使用过程中一直没有引用 R, // 那么 R 永远不会被构造 // 见文末的测试 // // 因此, 可以放心地当成 std::expect 来使用 // 因为正常情况下, 是不会有 E 的. // // std::optional 也是如此, 如果返回 nullopt, 那么 T 不会被构造 // 为避免 L 与 R 相同时造成编译错误, 用以下语句来禁用一部分成员函数: // template ::value, Dummy>::type> // 或者写成 // template ::value>> // 这两种语法都是合法的 // //----------------------------------------------------------------------------- namespace ECOM::Utility { template struct __tLeft { TL value; }; template struct __tRight { TR value; }; // 从 value 构造出 Left/Right 类型 template constexpr __tLeft left (const TL & _value) { return { _value }; } template constexpr __tRight right (const TR & _value) { return { _value }; } template constexpr __tLeft left (TL && _value) { return { std::move (_value) }; } template constexpr __tRight right (TR && _value) { return { std::move (_value) }; } template struct Either { template static constexpr bool dependent_false = false; public: using type_left = typename TL; using type_right = typename TR; private: std::variant < TL, TR > value; public: constexpr Either () = delete; // ! 不支持默认构造函数, 否则没法知道是左还是右 ! //< 拷贝构造函数及移动构造函数 constexpr Either (Either const & e) : value { e.value } {} constexpr Either (Either && e) : value { std::move (e.value) } {} //> //< 从 left 或 right 构造 constexpr Either (__tLeft const & _left) : value { _left.value } {} constexpr Either (__tRight const & _right) : value { _right.value } {} constexpr Either (__tLeft && _left) : value { std::move (_left.value) } {} constexpr Either (__tRight && _right) : value { std::move (_right.value) } {} //> //< 直接从 value 构造 // 但是只构造 left, 不构造 right; // 原因是, 调用者很难意识到: 是构造了 left, 还是构造了 right ? explicit constexpr Either (TL const & _left) : value { _left} {} explicit constexpr Either (TL && _left) : value { std::move (_left) } {} template ::value>> constexpr Either (TR const & _right) : value { _right } {} template ::value>> constexpr Either (TR && _right) : value { std::move (_right) } {} //> // 析构函数 ~Either () = default; public: // 赋值. ?? 只赋值一侧, 赋值后, 要清除另一侧吗 ?? constexpr Either & operator = (Either const & from) { value = from.value; return (*this); } constexpr Either & operator = (Either && from) { value = std::move (from.value); return (*this); } constexpr Either & operator = (TL const & _left) { value = _left; return (*this); } constexpr Either & operator = (TL && _left) { value = std::move (_left); return (*this); } template ::value>> constexpr Either & operator = (TR const & _right) { value = _right; return (*this); } template ::value>> constexpr Either & operator = (TR && _right) { value = std::move (_right); return (*this); } constexpr bool operator == (const Either & _with) const { return value == _with.value; } constexpr bool operator != (const Either & _with) const { return value != _with.value; } constexpr bool operator < (const Either & _with) const { return value < _with.value; } constexpr bool operator > (const Either & _with) const { return value > _with.value; } constexpr bool operator <= (const Either & _with) const { return value <= _with.value; } constexpr bool operator >= (const Either & _with) const { return value >= _with.value; } public: constexpr bool isLeft () const { return value.index () == 0; } constexpr bool isRight () const { return value.index () == 1; } constexpr operator bool () const { return value.index () == 0; } public: //< 禁止自动转换, 免得误转换了都不知道 constexpr operator TL () const = delete; template ::value>> constexpr operator TR () const = delete; //> public: //< 基于类型的判断和转换 // using dwString = ECOM::Utility::Either ; // auto b1 = dwAck.is (); // auto b2 = dwAck.is (); // const auto v1 = dwAck.get (); // const auto v2 = dwAck.get (); template constexpr bool is () const { static_assert (dependent_false , "only support or "); } template <> constexpr bool is () const { return value.index () == 0; } template <> constexpr bool is () const { return value.index () == 1; } template constexpr const T & get () const { static_assert (dependent_false , "only support or "); } template <> constexpr const TL & get () const { return getLeft (); } template <> constexpr const TR & get () const { return getRight (); } template constexpr const T * get_if () const { static_assert (dependent_false , "only support or "); } template <> constexpr const TL * get_if () const { return getIfLeft (); } template <> constexpr const TR * get_if () const { return getIfRight (); } //> public: //< 基于整数的判断和转换. 例子代码如下: // using dwString = ECOM::Utility::Either ; // auto b0 = dwAck.is <0> (); // auto b1 = dwAck.is <1> (); // const auto v0 = dwAck.get <0> (); // const auto v1 = dwAck.get <1> (); // eSTR::DString s0; eSTR::WString s1; // b0 = dwAck.to (s0); // b1 = dwAck.to (s1); template > constexpr bool is () const { return (value.index () == k); } template > constexpr const TL & get () const { return getLeft (); } template > constexpr const TR & get () const { return getRight (); } template > constexpr TL & get () { return getLeft (); } template > constexpr TR & get () { return getRight (); } // 如下写法, 语法上没问题, 但是容易导致编译器混淆如下两条语句: // ei.get <0> () // ei.get (); // 糟糕的是, 这两条语句的语义还是相反的 // template > // constexpr TL & get () { return getLeft (); } // template > // constexpr TR & get () { return getRight (); } template > constexpr const TL * get_if () const { return getIfLeft (); } template > constexpr const TR * get_if () const { return getIfRight (); } template > constexpr TL * get_if () { return getIfLeft (); } template > constexpr TR * get_if () { return getIfRight (); } public: //< template constexpr bool onLeftTo (T & _val) { if (value.index () == 0) { _val = std::get (value); return true; } return false; } template constexpr bool onRightTo (T & _val) { if (value.index () == 1) { _val = std::get (value); return true; } return false; } //> //< 两个 to 函数, 不需要事先判断. 如果可以, 就赋值给传入的参数. 返回: 是否赋值 constexpr bool to (TL & _val) { if (value.index () == 0) { _val = std::get (value); return true; } return false; } constexpr bool to (TR & _val) { if (value.index () == 1) { _val = std::get (value); return true; } return false; } //> public: //< 作为左侧或右侧返回其引用. 如果不匹配, std::get <> 扔一个例外 : std::bad_variant_access constexpr const TL & getLeft () const { return std::get (value); } constexpr const TR & getRight () const { return std::get (value); } constexpr TL & getLeft () { return std::get (value); } constexpr TR & getRight () { return std::get (value); } //> //< 作为左侧或右侧返回其指针. 如果不匹配, 返回 nullptr constexpr const TL * getIfLeft () const { return std::get_if (value); } constexpr const TR * getIfRight () const { return std::get_if (value); } constexpr TL * getIfLeft () { return std::get_if (value); } constexpr TR * getIfRight () { return std::get_if (value); } //> public: // 如果是 Left, 就执行指定的函数, 参数就是 leftValue template constexpr Either & onLeft (F && f, Args && ... args) { if (isLeft ()) f (getLeft (), std::forward (args)...); return (*this); } // 如果是 right, 就执行指定的函数, 参数就是 rightValue template constexpr Either & onRight (F && f, Args && ... args) { if (isRight ()) f (getRight (), std::forward (args)...); return (*this); } //> //< 映射 // 把我的 TL 作为参数, 施加于 F 函数, 最终映射成另外一个 either // 如果是左侧, 就用左侧传入给定的函数, 返回值也作为左侧 // 如果是右侧, 直接返回 // F 的返回值类型是 U, map () 的返回值类型是 Either // 某些语言把类似功能定义为 transform 函数 template constexpr auto map (F && f, Args && ... args) const & -> Either , TR> { if (isLeft ()) return { left (f (std::get (value), std::forward (args)...)) }; return { right (std::get (value)) }; } template constexpr auto map (F && f, Args && ... args) && -> Either , TR> { if (isLeft ()) return { left (f (std::move (std::get (value)), std::forward (args)...)) }; return { right (std::move (std::get (value))) }; } //> //< 带默认值的映射 //< 把我的 TL 作为参数, 作用到 F 函数上 // 如果是左侧, 就用左侧传入给定的函数, 然后返回 F 的返回值 // 如果是右侧, 返回默认值 // F 的返回值类型是 U, map_or () 的返回值类型也是 U template constexpr auto map_or (const U & u, F && f, Args && ... args) const & -> U { if (isLeft ()) return f (std::get (value), std::forward (args)...); return (u); } template constexpr auto map_or (U && u, F && f, Args && ... args) && -> U { if (isLeft ()) return f (std::move (std::get (value)), std::forward (args)...); return std::move (u); } //> //< 把我的 TL 作为参数, 调用 F 函数, 结果变成另外一个 either // 如果是左侧, 就用左侧传入给定的函数, 返回值也作为左侧 // 如果是右侧, 直接返回 // F 的返回值类型是 Either , 也就是说, 左值的类型可以变, 但是右值的类型不能变 // 比如 this 的类型是 , F 可以返回类型 , 但是不能返回类型 // 某些语言把类似功能定义为 flatMap 函数 template constexpr auto and_then (F && f, Args && ... args) const & -> typename std::invoke_result_t { if (isLeft ()) return { f (std::get (value), std::forward (args)...) }; return { right (std::get (value)) }; } template constexpr auto and_then (F && f, Args && ... args) && -> typename std::invoke_result_t { if (isLeft ()) return { f (std::move (std::get (value)), std::forward (args)...) }; return { right (std::move (std::get (value))) }; } //> //< 把我的 TR 作为参数, 调用 F 函数, 结果变成另外一个 either // 如果是右侧, 就用左侧传入给定的函数, 返回值也作为左侧 // 如果是左侧, 直接返回 // F 的返回值类型是 Either , 也就是说, 左值的类型不能变, 但是右值的类型可以变 // 比如 this 的类型是 , F 可以返回类型 , 但是不能返回类型 template constexpr auto or_else (F && f, Args && ... args) const & -> typename std::invoke_result_t { if (isRight ()) return { f (std::get (value), std::forward (args)...) }; return { left (std::get (value)) }; } template constexpr auto or_else (F && f, Args && ... args) && -> typename std::invoke_result_t { if (isRight ()) return { f (std::move (std::get (value)), std::forward (args)...) }; return { left (std::move (std::get (value))) }; } //> #if 0 // 编译出错: 函数重定义, 暂时禁用此功能 //< // 把 Either > 变换成 Either // 注意 共有类型 A // 比如把 Either > 变换成 Either // template , typename = std::enable_if_t ::value>> template ::value>> constexpr auto flatten () { if (isLeft ()) return Either { getLeft () }; return getRight (); } //> //< // 把 Either < , B> > 变换成 Either // 注意 共有类型 B // 比如把 Either < Either , string> 变换成 Either template ::value>> constexpr auto flatten () { if (isLeft ()) return getLeft (); return Either { getRight () }; } //> #endif #if 1 // 改成这种方式, 就不会导致编译错误了. 这两个函数的签名似乎不同 //< // 把 Either > 变换成 Either // 注意 共有类型 A // 比如把 Either > 变换成 Either template ::value>> constexpr auto flatten () { if (isLeft ()) return Either { getLeft () }; return getRight (); } //> //< // 把 Either < , B> > 变换成 Either // 注意 共有类型 B // 比如把 Either < Either , string> 变换成 Either template ::value>> constexpr auto flatten () { if (isLeft ()) return getLeft (); return Either { getRight () }; } //> #endif template constexpr auto join () const -> typename std::common_type ::type { using toType = typename std::common_type ::type; if (isLeft ()) return static_cast (std::get <0> (value)); else return static_cast (std::get <1> (value)); } public: constexpr static Either make (TL const & _left) { return Either { _left }; } constexpr static Either make (TL && _left) { return Either { std::move (_left) }; } template ::value>> constexpr static Either make (TR const & _right) { return Either { _right }; } template ::value>> constexpr static Either make (TR && _right) { return Either {std::move (_right) }; } template constexpr static Either from (Either && ei) { assert (ei.isLeft ()); return Either { std::move (ei.getLeft ()) }; } template constexpr static Either from (Either && ei) { assert (ei.isRight ()); return Either { std::move (ei.getRight ()) }; } }; // class Either template constexpr __tLeft left (Either && ei) { assert (ei.isLeft ()); return { std::move (ei.getLeft ()) }; } template constexpr __tRight right (Either && ei) { assert (ei.isRight ()); return { std::move (ei.getRight ()) }; } } /*//----------------------------------------------------------------------------- // 1. 如下语句, 编译通过且能运行 class XString { private: XString (); }; void Test () { using eiResult = ::Utility::Either ; eiResult x { ::Utility::left (2) }; auto y = std::move (x); int a = y.asLeft (); } // 2. 两个 Either 类型, 但是 TL 或 TR 相同, 可以用如下语句来转换 但是使用之前必须先判断类型 return eiResult { std::move (eiBLOBAck.getRight ()) }; // return eiResult { std::move (eiBLOBAck.get <1> ()) }; // return std::move (eiBLOBAck.getRight ()); *///-----------------------------------------------------------------------------