From ad9e50d917fd398b38f9aadc7f937f9ef66709b3 Mon Sep 17 00:00:00 2001 From: Yuming He Date: Thu, 6 Aug 2026 20:02:49 +0800 Subject: [PATCH] fix: enforce unexpected::operator== Mandates and fix its noexcept [expected.un.eq] mandates x.error() == y.error() be well-formed and its result be convertible to bool. Enforce it with a static_assert in the body so malformed comparisons get a clear diagnostic instead of obscure hard errors. Also fix the noexcept specifier: noexcept(lhs.error() == rhs.error()) only inspected the comparison, ignoring the implicit result-to-bool conversion performed by the return statement, so the operator could be declared noexcept yet terminate at runtime on a throwing conversion. Use expected_detail::is_nothrow_equality_result_convertible_to_bool_v, which covers the whole expression and matches the convention used by every other equality operator in this header. Signed-off-by: Yuming He --- include/zeus/expected.hpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/zeus/expected.hpp b/include/zeus/expected.hpp index 556a561..0463be4 100644 --- a/include/zeus/expected.hpp +++ b/include/zeus/expected.hpp @@ -240,8 +240,15 @@ class unexpected friend constexpr void swap(unexpected &x, unexpected &y) noexcept(noexcept(x.swap(y))) { x.swap(y); } template - friend constexpr bool operator==(const unexpected &lhs, const unexpected &rhs) noexcept(noexcept(lhs.error() == rhs.error())) + friend constexpr bool operator==( + const unexpected &lhs, const unexpected &rhs + ) noexcept(expected_detail::is_nothrow_equality_result_convertible_to_bool_v) { + // [expected.un.eq] Mandates + static_assert( + expected_detail::is_equality_result_convertible_to_bool_v, + "The expression lhs.error() == rhs.error() must be well-formed and its result must be convertible to bool" + ); return lhs.error() == rhs.error(); } template