Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions stl/inc/expected
Original file line number Diff line number Diff line change
Expand Up @@ -1159,21 +1159,21 @@ public:

template <class _Uty>
_NODISCARD friend constexpr bool operator==(const expected& _Left, const _Uty& _Right)
noexcept(noexcept(static_cast<bool>(_Left._Value == _Right))) /* strengthened */ {
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Value == _Right))) /* strengthened */ {
if (_Left._Has_value) {
return static_cast<bool>(_Left._Value == _Right);
return _Left._Value == _Right;
} else {
return false;
}
}

template <class _UErr>
_NODISCARD friend constexpr bool operator==(const expected& _Left, const unexpected<_UErr>& _Right)
noexcept(noexcept(static_cast<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
if (_Left._Has_value) {
return false;
} else {
return static_cast<bool>(_Left._Unexpected == _Right.error());
return _Left._Unexpected == _Right.error();
}
}

Expand Down Expand Up @@ -1890,21 +1890,25 @@ public:
template <class _Uty, class _UErr>
requires is_void_v<_Uty>
_NODISCARD friend constexpr bool operator==(const expected& _Left, const expected<_Uty, _UErr>& _Right)
noexcept(noexcept(static_cast<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
if (_Left._Has_value != _Right.has_value()) {
return false;
} else {
return _Left._Has_value || static_cast<bool>(_Left._Unexpected == _Right.error());
if (_Left._Has_value) {
return true;
} else {
return _Left._Unexpected == _Right.error();
}
}
}

template <class _UErr>
_NODISCARD friend constexpr bool operator==(const expected& _Left, const unexpected<_UErr>& _Right)
noexcept(noexcept(static_cast<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
noexcept(noexcept(_STD _Fake_copy_init<bool>(_Left._Unexpected == _Right.error()))) /* strengthened */ {
if (_Left._Has_value) {
return false;
} else {
return static_cast<bool>(_Left._Unexpected == _Right.error());
return _Left._Unexpected == _Right.error();
}
}

Expand Down
70 changes: 70 additions & 0 deletions tests/std/tests/P0323R12_expected/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2524,6 +2524,72 @@ static_assert(!is_constructible_v<expected<ConstructibleFromEverything, Converti
static_assert(!is_constructible_v<expected<ConstructibleFromEverything, ConvertibleFromInt>, unexpect_t>);
static_assert(!is_constructible_v<expected<ConstructibleFromEverything, ConvertibleFromInt>, const unexpect_t>);

// Test LWG-4366 "Heterogeneous comparison of expected may be ill-formed"
// Test taken from an example in the issue text
namespace test_lwg_4366 {
struct E1 {};
struct E2 {};

struct Bool {
constexpr operator bool() const {
return false;
}
constexpr explicit operator bool() = delete;
};

constexpr Bool operator==(E1, E2) {
return {};
}

constexpr void test() {
unexpected e1{E1{}};
unexpected e2{E2{}};
(void) (expected<int, E1>{e1} == e2);
(void) (expected<void, E1>{e1} == e2);
(void) (e1 == e2);
(void) (expected<int, E1>{e1} == expected<int, E2>{e2});
(void) (expected<void, E1>{e1} == expected<void, E2>{e2});
}

template <bool has_noexcept_operator_bool>
struct bool_with_noexcept {
constexpr operator bool() const noexcept(has_noexcept_operator_bool) {
return false;
}
};

// Test that operator== has correct noexcept specification (based on noexcept specs of underlying expressions)

struct E3 {};
template <bool has_noexcept_operator_bool>
struct E4 {};

template <bool X>
constexpr bool_with_noexcept<X> operator==(E3, E4<X>) noexcept {
return {};
}

template <bool has_noexcept_operator_bool>
constexpr void test2() {
unexpected e3{E3{}};
unexpected e4{E4<has_noexcept_operator_bool>{}};

(void) (expected<int, E3>{e3} == e4);
(void) (expected<void, E3>{e3} == e4);
(void) (e3 == e4);
(void) (expected<int, E3>{e3} == expected<int, E4<has_noexcept_operator_bool>>{e4});
(void) (expected<void, E3>{e3} == expected<void, E4<has_noexcept_operator_bool>>{e4});

static_assert(has_noexcept_operator_bool == noexcept(expected<int, E3>{e3} == e4));
static_assert(has_noexcept_operator_bool == noexcept(expected<void, E3>{e3} == e4));
static_assert(has_noexcept_operator_bool == noexcept(e3 == e4));
static_assert(has_noexcept_operator_bool
== noexcept(expected<int, E3>{e3} == expected<int, E4<has_noexcept_operator_bool>>{e4}));
static_assert(has_noexcept_operator_bool
== noexcept(expected<void, E3>{e3} == expected<void, E4<has_noexcept_operator_bool>>{e4}));
}
} // namespace test_lwg_4366

int main() {
test_unexpected::test_all();
static_assert(test_unexpected::test_all());
Expand All @@ -2543,4 +2609,8 @@ int main() {
test_lwg_3886();
test_lwg_3886_volatile();
test_inherited_constructors();

test_lwg_4366::test();
test_lwg_4366::test2<true>();
test_lwg_4366::test2<false>();
}