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
78 changes: 32 additions & 46 deletions stl/inc/expected
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,28 @@ struct _Check_expected_argument : true_type {

_EXPORT_STD template <class _Ty, class _Err>
class expected {
private:
static_assert(_Check_expected_argument<_Ty>::value);
static_assert(_Check_unexpected_argument<_Err>::value);

template <class _UTy, class _UErr>
friend class expected;

template <class _Uty, class _UErr>
static constexpr bool _Allow_unwrapping = disjunction_v<is_same<remove_cv_t<_Ty>, bool>,
negation<disjunction<is_constructible<_Ty, expected<_Uty, _UErr>&>, //
is_constructible<_Ty, expected<_Uty, _UErr>>, //
is_constructible<_Ty, const expected<_Uty, _UErr>&>, //
is_constructible<_Ty, const expected<_Uty, _UErr>>, //
is_convertible<expected<_Uty, _UErr>&, _Ty>, //
is_convertible<expected<_Uty, _UErr>&&, _Ty>, //
is_convertible<const expected<_Uty, _UErr>&, _Ty>, //
is_convertible<const expected<_Uty, _UErr>&&, _Ty>>>> //
&& !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>&> //
&& !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>> //
&& !is_constructible_v<unexpected<_Err>, const expected<_Uty, _UErr>&> //
&& !is_constructible_v<unexpected<_Err>, const expected<_Uty, _UErr>>;

public:
using value_type = _Ty;
using error_type = _Err;
Expand Down Expand Up @@ -238,23 +254,8 @@ public:
// clang-format on

template <class _Uty, class _UErr>
static constexpr bool _Allow_unwrapping = disjunction_v<is_same<remove_cv_t<_Ty>, bool>,
negation<disjunction<is_constructible<_Ty, expected<_Uty, _UErr>&>, //
is_constructible<_Ty, expected<_Uty, _UErr>>, //
is_constructible<_Ty, const expected<_Uty, _UErr>&>, //
is_constructible<_Ty, const expected<_Uty, _UErr>>, //
is_convertible<expected<_Uty, _UErr>&, _Ty>, //
is_convertible<expected<_Uty, _UErr>&&, _Ty>, //
is_convertible<const expected<_Uty, _UErr>&, _Ty>, //
is_convertible<const expected<_Uty, _UErr>&&, _Ty>>>> //
&& !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>&> //
&& !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>> //
&& !is_constructible_v<unexpected<_Err>, const expected<_Uty, _UErr>&> //
&& !is_constructible_v<unexpected<_Err>, const expected<_Uty, _UErr>>;
Copy link
Contributor Author

@achabense achabense Sep 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for my untimely reply; if it's late to make new pushes and these changes look ok, I will carry these changes to another pr.

  1. I think it's beneficial not to relocate _Allow_unwrapping here and in expected<void, ...>, as it is used closely after definition so its function can be more obvious.
  2. These can also be private:
    struct _NODISCARD _GuardTy {

    static constexpr void _Reinit_expected(_First& _New_val, _Second& _Old_val, _Args&&... _Vals) noexcept(


template <class _Uty, class _UErr>
requires is_constructible_v<_Ty, const _Uty&> && is_constructible_v<_Err, const _UErr&>
&& _Allow_unwrapping<_Uty, _UErr>
requires _Different_from<expected<_Uty, _UErr>, expected> && is_constructible_v<_Ty, const _Uty&>
&& is_constructible_v<_Err, const _UErr&> && _Allow_unwrapping<_Uty, _UErr>
constexpr explicit(!is_convertible_v<const _Uty&, _Ty> || !is_convertible_v<const _UErr&, _Err>)
expected(const expected<_Uty, _UErr>& _Other) noexcept(is_nothrow_constructible_v<_Ty, const _Uty&> //
&& is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened
Expand All @@ -267,7 +268,8 @@ public:
}

template <class _Uty, class _UErr>
requires is_constructible_v<_Ty, _Uty> && is_constructible_v<_Err, _UErr> && _Allow_unwrapping<_Uty, _UErr>
requires _Different_from<expected<_Uty, _UErr>, expected> && is_constructible_v<_Ty, _Uty>
&& is_constructible_v<_Err, _UErr> && _Allow_unwrapping<_Uty, _UErr>
constexpr explicit(!is_convertible_v<_Uty, _Ty> || !is_convertible_v<_UErr, _Err>)
expected(expected<_Uty, _UErr>&& _Other) noexcept(
is_nothrow_constructible_v<_Ty, _Uty>&& is_nothrow_constructible_v<_Err, _UErr>) // strengthened
Expand Down Expand Up @@ -1161,11 +1163,18 @@ private:
template <class _Ty, class _Err>
requires is_void_v<_Ty>
class expected<_Ty, _Err> {
private:
static_assert(_Check_unexpected_argument<_Err>::value);

template <class _UTy, class _UErr>
friend class expected;

template <class _Uty, class _UErr>
static constexpr bool _Allow_unwrapping = !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>&>
&& !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>>
&& !is_constructible_v<unexpected<_Err>, const expected<_Uty, _UErr>&>
&& !is_constructible_v<unexpected<_Err>, const expected<_Uty, _UErr>>;

public:
using value_type = _Ty;
using error_type = _Err;
Expand Down Expand Up @@ -1202,13 +1211,8 @@ public:
// clang-format on

template <class _Uty, class _UErr>
static constexpr bool _Allow_unwrapping = !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>&>
&& !is_constructible_v<unexpected<_Err>, expected<_Uty, _UErr>>
&& !is_constructible_v<unexpected<_Err>, const expected<_Uty, _UErr>&>
&& !is_constructible_v<unexpected<_Err>, const expected<_Uty, _UErr>>;

template <class _Uty, class _UErr>
requires is_void_v<_Uty> && is_constructible_v<_Err, const _UErr&> && _Allow_unwrapping<_Uty, _UErr>
requires _Different_from<expected<_Uty, _UErr>, expected> && is_void_v<_Uty>
&& is_constructible_v<_Err, const _UErr&> && _Allow_unwrapping<_Uty, _UErr>
constexpr explicit(!is_convertible_v<const _UErr&, _Err>) expected(const expected<_Uty, _UErr>& _Other) noexcept(
is_nothrow_constructible_v<_Err, const _UErr&>) // strengthened
: _Has_value(_Other._Has_value) {
Expand All @@ -1218,7 +1222,8 @@ public:
}

template <class _Uty, class _UErr>
requires is_void_v<_Uty> && is_constructible_v<_Err, _UErr> && _Allow_unwrapping<_Uty, _UErr>
requires _Different_from<expected<_Uty, _UErr>, expected> && is_void_v<_Uty> && is_constructible_v<_Err, _UErr>
&& _Allow_unwrapping<_Uty, _UErr>
constexpr explicit(!is_convertible_v<_UErr, _Err>)
expected(expected<_Uty, _UErr>&& _Other) noexcept(is_nothrow_constructible_v<_Err, _UErr>) // strengthened
: _Has_value(_Other._Has_value) {
Expand Down Expand Up @@ -1380,26 +1385,7 @@ public:
is_nothrow_move_constructible_v<_Err>&& is_nothrow_swappable_v<_Err>)
requires is_swappable_v<_Err> && is_move_constructible_v<_Err>
{
using _STD swap;
if (_Left._Has_value && _Right._Has_value) {
// nothing
} else if (_Left._Has_value) {
_STD construct_at(_STD addressof(_Left._Unexpected), _STD move(_Right._Unexpected));
if constexpr (!is_trivially_destructible_v<_Err>) {
_Right._Unexpected.~_Err();
}
_Left._Has_value = false;
_Right._Has_value = true;
} else if (_Right._Has_value) {
_STD construct_at(_STD addressof(_Right._Unexpected), _STD move(_Left._Unexpected));
if constexpr (!is_trivially_destructible_v<_Err>) {
_Left._Unexpected.~_Err();
}
_Left._Has_value = true;
_Right._Has_value = false;
} else {
swap(_Left._Unexpected, _Right._Unexpected); // intentional ADL
}
_Left.swap(_Right);
}

// [expected.void.obs]
Expand Down
5 changes: 5 additions & 0 deletions tests/std/tests/P0323R12_expected/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#define _CONTAINER_DEBUG_LEVEL 1

#include <any>
#include <cassert>
#include <concepts>
#include <exception>
Expand Down Expand Up @@ -2135,6 +2136,10 @@ void test_lwg_3843() {
}
}

// Test GH-4011: these predicates triggered constraint recursion.
static_assert(copyable<expected<any, int>>);
static_assert(copyable<expected<void, any>>);

int main() {
test_unexpected::test_all();
static_assert(test_unexpected::test_all());
Expand Down