Re-enable left_opt() and right_opt() for rvalue references

This commit is contained in:
Sebastian Messmer 2018-12-24 18:54:22 +01:00
parent 2878313993
commit 4de6f1d8d9

View File

@ -8,9 +8,9 @@
namespace cpputils { namespace cpputils {
template<class Left, class Right> template<class Left, class Right>
class either final { class either final {
public: public:
template<class Head, class... Tail, std::enable_if_t<std::is_constructible<Left, Head, Tail...>::value && !std::is_constructible<Right, Head, Tail...>::value>* = nullptr> template<class Head, class... Tail, std::enable_if_t<std::is_constructible<Left, Head, Tail...>::value && !std::is_constructible<Right, Head, Tail...>::value>* = nullptr>
either(Head&& construct_left_head_arg, Tail&&... construct_left_tail_args) noexcept(noexcept(std::declval<either<Left, Right>>()._construct_left(std::forward<Head>(construct_left_head_arg), std::forward<Tail>(construct_left_tail_args)...))) either(Head&& construct_left_head_arg, Tail&&... construct_left_tail_args) noexcept(noexcept(std::declval<either<Left, Right>>()._construct_left(std::forward<Head>(construct_left_head_arg), std::forward<Tail>(construct_left_tail_args)...)))
: _side(Side::left) { : _side(Side::left) {
@ -115,7 +115,14 @@ namespace cpputils {
return boost::none; return boost::none;
} }
} }
// left_opt()&& not offered because optional<Left&&> doesn't work // warning: opposed to the other left_opt variants, this one already moves the content and returns by value.
boost::optional<Left> left_opt() && noexcept(noexcept(boost::optional<Left>(std::move(_left)))) {
if (_side == Side::left) {
return std::move(_left);
} else {
return boost::none;
}
}
boost::optional<const Right&> right_opt() const& noexcept { boost::optional<const Right&> right_opt() const& noexcept {
if (_side == Side::right) { if (_side == Side::right) {
@ -131,9 +138,16 @@ namespace cpputils {
return boost::none; return boost::none;
} }
} }
// right_opt()&& not offered because optional<Right&&> doesn't work // warning: opposed to the other left_opt variants, this one already moves the content and returns by value.
boost::optional<Right> right_opt() && noexcept(noexcept(boost::optional<Right>(std::move(_right)))) {
if (_side == Side::right) {
return std::move(_right);
} else {
return boost::none;
}
}
private: private:
union { union {
Left _left; Left _left;
Right _right; Right _right;
@ -163,10 +177,10 @@ namespace cpputils {
template<typename Left_, typename Right_, typename... Args> template<typename Left_, typename Right_, typename... Args>
friend either<Left_, Right_> make_right(Args&&... args) /* TODO noexcept(noexcept(std::declval<either<Left, Right>>()._construct_right(std::forward<Args>(args)...))) */; friend either<Left_, Right_> make_right(Args&&... args) /* TODO noexcept(noexcept(std::declval<either<Left, Right>>()._construct_right(std::forward<Args>(args)...))) */;
}; };
template<class Left, class Right> template<class Left, class Right>
inline bool operator==(const either<Left, Right> &lhs, const either<Left, Right> &rhs) noexcept(noexcept(std::declval<Left>() == std::declval<Left>()) && noexcept(std::declval<Right>() == std::declval<Right>())) { inline bool operator==(const either<Left, Right> &lhs, const either<Left, Right> &rhs) noexcept(noexcept(std::declval<Left>() == std::declval<Left>()) && noexcept(std::declval<Right>() == std::declval<Right>())) {
if (lhs.is_left() != rhs.is_left()) { if (lhs.is_left() != rhs.is_left()) {
return false; return false;
} }
@ -175,36 +189,36 @@ namespace cpputils {
} else { } else {
return lhs.right() == rhs.right(); return lhs.right() == rhs.right();
} }
} }
template<class Left, class Right> template<class Left, class Right>
inline bool operator!=(const either<Left, Right> &lhs, const either<Left, Right> &rhs) noexcept(noexcept(operator==(lhs, rhs))) { inline bool operator!=(const either<Left, Right> &lhs, const either<Left, Right> &rhs) noexcept(noexcept(operator==(lhs, rhs))) {
return !operator==(lhs, rhs); return !operator==(lhs, rhs);
} }
template<class Left, class Right> template<class Left, class Right>
inline std::ostream &operator<<(std::ostream &stream, const either<Left, Right> &value) { inline std::ostream &operator<<(std::ostream &stream, const either<Left, Right> &value) {
if (value.is_left()) { if (value.is_left()) {
stream << "Left(" << value.left() << ")"; stream << "Left(" << value.left() << ")";
} else { } else {
stream << "Right(" << value.right() << ")"; stream << "Right(" << value.right() << ")";
} }
return stream; return stream;
} }
template<typename Left, typename Right, typename... Args> template<typename Left, typename Right, typename... Args>
inline either<Left, Right> make_left(Args&&... args) /* TODO noexcept(noexcept(std::declval<either<Left, Right>>()._construct_left(std::forward<Args>(args)...))) */ { inline either<Left, Right> make_left(Args&&... args) /* TODO noexcept(noexcept(std::declval<either<Left, Right>>()._construct_left(std::forward<Args>(args)...))) */ {
either<Left, Right> result(either<Left, Right>::Side::left); either<Left, Right> result(either<Left, Right>::Side::left);
result._construct_left(std::forward<Args>(args)...); result._construct_left(std::forward<Args>(args)...);
return result; return result;
} }
template<typename Left, typename Right, typename... Args> template<typename Left, typename Right, typename... Args>
inline either<Left, Right> make_right(Args&&... args) /* TODO noexcept(noexcept(std::declval<either<Left, Right>>()._construct_right(std::forward<Args>(args)...))) */ { inline either<Left, Right> make_right(Args&&... args) /* TODO noexcept(noexcept(std::declval<either<Left, Right>>()._construct_right(std::forward<Args>(args)...))) */ {
either<Left, Right> result(either<Left, Right>::Side::right); either<Left, Right> result(either<Left, Right>::Side::right);
result._construct_right(std::forward<Args>(args)...); result._construct_right(std::forward<Args>(args)...);
return result; return result;
} }
} }