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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Implemented LWG Issues:
- [x] [LWG-3940](https://wg21.link/lwg3940) `std::expected<void, E>::value()` also needs `E` to be copy constructible
- [x] [LWG-4026](https://wg21.link/lwg4026) Assignment operators of `std::expected` should propagate triviality
- [x] [LWG-3877](https://wg21.link/lwg3877) incorrect constraints on const-qualified monadic overloads for `std::expected`
- [x] [LWG-3886](https://wg21.link/lwg3886) Monad mo' problems

Enhancements:

Expand Down
38 changes: 27 additions & 11 deletions include/zeus/expected.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,10 @@ struct copy_assign_base<T, E, true, false> : move_ctor_base<T, E>
copy_assign_base(copy_assign_base &&rhs) = default;

constexpr copy_assign_base &operator=(const copy_assign_base &rhs) //
noexcept(std::is_nothrow_copy_constructible_v<T> && std::is_nothrow_copy_assignable_v<T> && std::is_nothrow_copy_constructible_v<E> && std::is_nothrow_copy_assignable_v<E>)
noexcept(
std::is_nothrow_copy_constructible_v<T> && std::is_nothrow_copy_assignable_v<T> && std::is_nothrow_copy_constructible_v<E> &&
std::is_nothrow_copy_assignable_v<E>
)
{
if (this->m_has_val && rhs.m_has_val)
{
Expand Down Expand Up @@ -1063,7 +1066,10 @@ struct move_assign_base<T, E, true, false> : copy_assign_base<T, E>
move_assign_base &operator=(const move_assign_base &rhs) = default;

constexpr move_assign_base &operator=(move_assign_base &&rhs) //
noexcept(std::is_nothrow_move_constructible_v<T> && std::is_nothrow_move_assignable_v<T> && std::is_nothrow_move_constructible_v<E> && std::is_nothrow_move_assignable_v<E>)
noexcept(
std::is_nothrow_move_constructible_v<T> && std::is_nothrow_move_assignable_v<T> && std::is_nothrow_move_constructible_v<E> &&
std::is_nothrow_move_assignable_v<E>
)
{
if (this->m_has_val && rhs.m_has_val)
{
Expand Down Expand Up @@ -1194,6 +1200,9 @@ class expected
typedef E error_type;
typedef unexpected<E> unexpected_type;

template<class U>
using rebind = expected<U, error_type>;

// default constructors

constexpr expected() = default;
Expand Down Expand Up @@ -1286,15 +1295,18 @@ class expected
// expected(U &&)

// implicit
template<class U = T, std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr, expected_detail::enable_forward_t<T, E, U> * = nullptr>
template<
class U = std::remove_cv_t<T>,
std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr,
expected_detail::enable_forward_t<T, E, U> * = nullptr>
constexpr expected(U &&v) noexcept(std::is_nothrow_constructible_v<T, U>)
: expected(std::in_place, std::forward<U>(v))
{
}

// explicit
template<
class U = T,
class U = std::remove_cv_t<T>,
std::enable_if_t<!std::is_convertible_v<U, T>> * = nullptr,
expected_detail::enable_forward_t<T, E, U> * = nullptr>
constexpr explicit expected(U &&v) noexcept(std::is_nothrow_constructible_v<T, U>)
Expand Down Expand Up @@ -1418,7 +1430,7 @@ class expected
// assignments

template<
class U = T, //
class U = std::remove_cv_t<T>,
std::enable_if_t< //
!std::is_same_v<expected, expected_detail::remove_cvref_t<U>> && //
!expected_detail::is_specialization_v<expected_detail::remove_cvref_t<U>, unexpected> && //
Expand Down Expand Up @@ -1544,14 +1556,15 @@ class expected
}

template<class OT = T, class OE = E>
constexpr
std::enable_if_t<
constexpr std::enable_if_t<
std::is_swappable_v<OT> && std::is_swappable_v<OE> && //
std::is_move_constructible_v<OT> && std::is_move_constructible_v<OE> && //
(std::is_nothrow_move_constructible_v<OT> || std::is_nothrow_move_constructible_v<OE>)>
swap(expected &rhs) //
noexcept(std::is_nothrow_move_constructible_v<T> && std::is_nothrow_swappable_v<T> && //
std::is_nothrow_move_constructible_v<E> && std::is_nothrow_swappable_v<E>)
noexcept(
std::is_nothrow_move_constructible_v<T> && std::is_nothrow_swappable_v<T> && //
std::is_nothrow_move_constructible_v<E> && std::is_nothrow_swappable_v<E>
)
{
using std::swap;
if (this->m_has_val && rhs.m_has_val)
Expand Down Expand Up @@ -1688,7 +1701,7 @@ class expected
return std::move(err());
}

template<class U>
template<class U = std::remove_cv_t<T>>
constexpr T value_or(U &&v) const & //
noexcept(std::is_nothrow_copy_constructible_v<T> && expected_detail::is_nothrow_convertible_v<U, T>)
{
Expand All @@ -1703,7 +1716,7 @@ class expected
return static_cast<T>(std::forward<U>(v));
}
}
template<class U>
template<class U = std::remove_cv_t<T>>
constexpr T value_or(U &&v) && //
noexcept(std::is_nothrow_move_constructible_v<T> && expected_detail::is_nothrow_convertible_v<U, T>)
{
Expand Down Expand Up @@ -2143,6 +2156,9 @@ class expected<void, E>
typedef E error_type;
typedef unexpected<E> unexpected_type;

template<class U>
using rebind = expected<U, error_type>;

constexpr expected() = default;
constexpr expected(const expected &rhs) = default;
constexpr expected(expected &&rhs) = default;
Expand Down
1 change: 1 addition & 0 deletions tests/test_expected/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ set(SOURCES
monadic_tests.cpp
noexcept_tests.cpp
equality_tests.cpp
lwg_3886_tests.cpp
test_expected_main.cpp
)

Expand Down
72 changes: 72 additions & 0 deletions tests/test_expected/lwg_3886_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include <catch2/catch_all.hpp>

#include <zeus/expected.hpp>

using namespace zeus;

namespace
{

struct ConstructModeDistinction
{
enum ConstructedMode
{
kDefault,
kCopy,
kMove,
kCopyAssign,
kMoveAssign,
};

constexpr ConstructModeDistinction() noexcept
: mode(kDefault)
{
}
constexpr ConstructModeDistinction(ConstructModeDistinction const&) noexcept
: mode(kCopy)
{
}
constexpr ConstructModeDistinction(ConstructModeDistinction&&) noexcept
: mode(kMove)
{
}
constexpr ConstructModeDistinction& operator=(ConstructModeDistinction&&) noexcept
{
mode = kMoveAssign;
return *this;
}
constexpr ConstructModeDistinction& operator=(ConstructModeDistinction const&) noexcept
{
mode = kCopyAssign;
return *this;
}

ConstructedMode mode;
};

} // namespace

SCENARIO("Monad mo' problems", "[LWG-3886]")
{
using T = const ConstructModeDistinction;
using E = int;

// FIXME LWG-3891
//SECTION("constructor")
//{
// expected<T, E> const e({});
// CHECK(e.value().mode == T::kMove);
//}
//SECTION("assignment")
//{
// expected<T, E> e {zeus::unexpect};
// e = {};
// CHECK(e.value().mode == T::kMove);
//}

SECTION("value_or()")
{
expected<T, E> const e {zeus::unexpect};
CHECK(e.value_or({}).mode == T::kMove);
}
}
2 changes: 2 additions & 0 deletions tests/third_party/msvc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
include_directories(SYSTEM "include")

add_subdirectory(msvc_stl_p0323r12_test)
if (MSVC_TOOLSET_VERSION GREATER_EQUAL 143)
# can only built with v143 and later
Expand Down
31 changes: 31 additions & 0 deletions tests/third_party/msvc/include/is_permissive.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#pragma once

#include <yvals_core.h>

namespace detail {
constexpr bool permissive() {
return false;
}

template <class>
struct PermissiveTestBase {
static constexpr bool permissive() {
return true;
}
};

template <class T>
struct PermissiveTest : PermissiveTestBase<T> {
static constexpr bool test() {
return permissive();
}
};
} // namespace detail

template <class T>
constexpr bool is_permissive_v = detail::PermissiveTest<T>::test();

_INLINE_VAR constexpr bool is_permissive = is_permissive_v<int>;
Loading