From 5e9b29c055089d9dbbc36697d2df64c654af6ada Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Fri, 9 Feb 2024 15:34:43 +0200 Subject: [PATCH] Add sfinae on comparison operators; fix formatting #verification #docs #sonar --- include/cetl/pf17/optional.hpp | 98 +++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 30 deletions(-) diff --git a/include/cetl/pf17/optional.hpp b/include/cetl/pf17/optional.hpp index 58153c82..7ba25907 100644 --- a/include/cetl/pf17/optional.hpp +++ b/include/cetl/pf17/optional.hpp @@ -204,9 +204,9 @@ struct base_move_construction : base_copy_construction /// COPY ASSIGNMENT POLICY template ::value && // - std::is_trivially_copy_constructible::value && // - std::is_trivially_destructible::value> + bool = std::is_trivially_copy_assignable::value&& // + std::is_trivially_copy_constructible::value&& // + std::is_trivially_destructible::value> struct base_copy_assignment; /// Trivially copy assignable case. template @@ -223,7 +223,7 @@ struct base_copy_assignment : base_move_construction constexpr base_copy_assignment(const base_copy_assignment&) noexcept = default; constexpr base_copy_assignment(base_copy_assignment&&) noexcept = default; constexpr base_copy_assignment& operator=(const base_copy_assignment& other) noexcept( - std::is_nothrow_copy_assignable::value && std::is_nothrow_copy_constructible::value) + std::is_nothrow_copy_assignable::value&& std::is_nothrow_copy_constructible::value) { if (this->m_engaged && other.m_engaged) { @@ -246,9 +246,9 @@ struct base_copy_assignment : base_move_construction /// MOVE ASSIGNMENT POLICY template ::value && // - std::is_trivially_move_constructible::value && // - std::is_trivially_destructible::value> + bool = std::is_trivially_move_assignable::value&& // + std::is_trivially_move_constructible::value&& // + std::is_trivially_destructible::value> struct base_move_assignment; /// Trivially move assignable case. template @@ -266,7 +266,7 @@ struct base_move_assignment : base_copy_assignment constexpr base_move_assignment(base_move_assignment&&) noexcept = default; constexpr base_move_assignment& operator=(const base_move_assignment&) noexcept = default; constexpr base_move_assignment& operator=(base_move_assignment&& other) noexcept( - std::is_nothrow_move_assignable::value && std::is_nothrow_move_constructible::value) + std::is_nothrow_move_assignable::value&& std::is_nothrow_move_constructible::value) { if (this->m_engaged && other.m_engaged) { @@ -335,6 +335,8 @@ constexpr bool enable_ctor8 = (!(std::is_same, bool>::value && is_optional>::value)) && // (std::is_convertible::value != Explicit); +template +using enable_comparison = std::enable_if_t::value, bool>; } // namespace opt } // namespace detail @@ -440,8 +442,8 @@ class optional : private detail::opt::base_move_assignment, optional& operator=(const optional& other) = default; /// Assignment 3 - constexpr optional& operator=(optional&& other) noexcept(std::is_nothrow_move_assignable::value && - std::is_nothrow_move_constructible::value) = default; + constexpr optional& operator=(optional&& other) noexcept( + std::is_nothrow_move_assignable::value&& std::is_nothrow_move_constructible::value) = default; /// Assignment 4 template , } /// Swaps two optionals. If either is not engaged, acts like move assignment. - void swap(optional& other) noexcept(std::is_nothrow_move_constructible::value && // - std::is_nothrow_swappable::value) + void swap(optional& other) noexcept(std::is_nothrow_move_constructible::value&& // + std::is_nothrow_swappable::value) { using std::swap; if (has_value() && other.has_value()) @@ -658,32 +660,44 @@ class optional : private detail::opt::base_move_assignment, /// - lhs is considered less than rhs if, and only if, rhs contains a value and lhs does not. /// @{ template -constexpr bool operator==(const optional& lhs, const optional& rhs) +constexpr detail::opt::enable_comparison() == std::declval())> operator==( + const optional& lhs, + const optional& rhs) { return (lhs.has_value() == rhs.has_value()) && ((!lhs.has_value()) || ((*lhs) == (*rhs))); } template -constexpr bool operator!=(const optional& lhs, const optional& rhs) +constexpr detail::opt::enable_comparison() != std::declval())> operator!=( + const optional& lhs, + const optional& rhs) { return !(lhs == rhs); } template -constexpr bool operator<(const optional& lhs, const optional& rhs) +constexpr detail::opt::enable_comparison() < std::declval())> operator<( + const optional& lhs, + const optional& rhs) { return rhs.has_value() && ((!lhs.has_value()) || (*lhs) < (*rhs)); } template -constexpr bool operator<=(const optional& lhs, const optional& rhs) +constexpr detail::opt::enable_comparison() <= std::declval())> operator<=( + const optional& lhs, + const optional& rhs) { return !(rhs < lhs); } template -constexpr bool operator>(const optional& lhs, const optional& rhs) +constexpr detail::opt::enable_comparison() > std::declval())> operator>( + const optional& lhs, + const optional& rhs) { return rhs < lhs; } template -constexpr bool operator>=(const optional& lhs, const optional& rhs) +constexpr detail::opt::enable_comparison() >= std::declval())> operator>=( + const optional& lhs, + const optional& rhs) { return !(lhs < rhs); } @@ -759,62 +773,86 @@ constexpr bool operator>=(const nullopt_t, const optional& opt) noexcept /// Otherwise, the optional is considered less than value. /// @{ template -constexpr bool operator==(const optional& opt, const U& value) +constexpr detail::opt::enable_comparison() == std::declval())> operator==( + const optional& opt, + const U& value) { return opt.has_value() && ((*opt) == value); } template -constexpr bool operator==(const T& value, const optional& opt) +constexpr detail::opt::enable_comparison() == std::declval())> operator==( + const T& value, + const optional& opt) { return opt.has_value() && (value == (*opt)); } template -constexpr bool operator!=(const optional& opt, const U& value) +constexpr detail::opt::enable_comparison() != std::declval())> operator!=( + const optional& opt, + const U& value) { return (!opt.has_value()) || ((*opt) != value); } template -constexpr bool operator!=(const T& value, const optional& opt) +constexpr detail::opt::enable_comparison() != std::declval())> operator!=( + const T& value, + const optional& opt) { return (!opt.has_value()) || ((*opt) != value); } template -constexpr bool operator<(const optional& opt, const U& value) +constexpr detail::opt::enable_comparison() < std::declval())> operator<( + const optional& opt, + const U& value) { return (!opt.has_value()) || ((*opt) < value); } template -constexpr bool operator<(const T& value, const optional& opt) +constexpr detail::opt::enable_comparison() < std::declval())> operator<( + const T& value, + const optional& opt) { return opt.has_value() && (value < (*opt)); } template -constexpr bool operator<=(const optional& opt, const U& value) +constexpr detail::opt::enable_comparison() <= std::declval())> operator<=( + const optional& opt, + const U& value) { return (!opt.has_value()) || ((*opt) <= value); } template -constexpr bool operator<=(const T& value, const optional& opt) +constexpr detail::opt::enable_comparison() <= std::declval())> operator<=( + const T& value, + const optional& opt) { return opt.has_value() && (value <= (*opt)); } template -constexpr bool operator>(const optional& opt, const U& value) +constexpr detail::opt::enable_comparison() > std::declval())> operator>( + const optional& opt, + const U& value) { return opt.has_value() && ((*opt) > value); } template -constexpr bool operator>(const T& value, const optional& opt) +constexpr detail::opt::enable_comparison() > std::declval())> operator>( + const T& value, + const optional& opt) { return (!opt.has_value()) || (value > (*opt)); } template -constexpr bool operator>=(const optional& opt, const U& value) +constexpr detail::opt::enable_comparison() >= std::declval())> operator>=( + const optional& opt, + const U& value) { return opt.has_value() && ((*opt) >= value); } template -constexpr bool operator>=(const T& value, const optional& opt) +constexpr detail::opt::enable_comparison() >= std::declval())> operator>=( + const T& value, + const optional& opt) { return (!opt.has_value()) || (value >= (*opt)); }