Skip to content

Commit 361a337

Browse files
authored
Merge pull request #13 from zeus-cpp/feat-lwg-3886
Implement LWG-3886 and add missing template 'rebind'
2 parents c2a6d6a + 9d5e45c commit 361a337

File tree

8 files changed

+380
-60
lines changed

8 files changed

+380
-60
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Implemented LWG Issues:
1717
- [x] [LWG-3940](https://wg21.link/lwg3940) `std::expected<void, E>::value()` also needs `E` to be copy constructible
1818
- [x] [LWG-4026](https://wg21.link/lwg4026) Assignment operators of `std::expected` should propagate triviality
1919
- [x] [LWG-3877](https://wg21.link/lwg3877) incorrect constraints on const-qualified monadic overloads for `std::expected`
20+
- [x] [LWG-3886](https://wg21.link/lwg3886) Monad mo' problems
2021

2122
Enhancements:
2223

include/zeus/expected.hpp

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,10 @@ struct copy_assign_base<T, E, true, false> : move_ctor_base<T, E>
942942
copy_assign_base(copy_assign_base &&rhs) = default;
943943

944944
constexpr copy_assign_base &operator=(const copy_assign_base &rhs) //
945-
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>)
945+
noexcept(
946+
std::is_nothrow_copy_constructible_v<T> && std::is_nothrow_copy_assignable_v<T> && std::is_nothrow_copy_constructible_v<E> &&
947+
std::is_nothrow_copy_assignable_v<E>
948+
)
946949
{
947950
if (this->m_has_val && rhs.m_has_val)
948951
{
@@ -1063,7 +1066,10 @@ struct move_assign_base<T, E, true, false> : copy_assign_base<T, E>
10631066
move_assign_base &operator=(const move_assign_base &rhs) = default;
10641067

10651068
constexpr move_assign_base &operator=(move_assign_base &&rhs) //
1066-
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>)
1069+
noexcept(
1070+
std::is_nothrow_move_constructible_v<T> && std::is_nothrow_move_assignable_v<T> && std::is_nothrow_move_constructible_v<E> &&
1071+
std::is_nothrow_move_assignable_v<E>
1072+
)
10671073
{
10681074
if (this->m_has_val && rhs.m_has_val)
10691075
{
@@ -1194,6 +1200,9 @@ class expected
11941200
typedef E error_type;
11951201
typedef unexpected<E> unexpected_type;
11961202

1203+
template<class U>
1204+
using rebind = expected<U, error_type>;
1205+
11971206
// default constructors
11981207

11991208
constexpr expected() = default;
@@ -1286,15 +1295,18 @@ class expected
12861295
// expected(U &&)
12871296

12881297
// implicit
1289-
template<class U = T, std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr, expected_detail::enable_forward_t<T, E, U> * = nullptr>
1298+
template<
1299+
class U = std::remove_cv_t<T>,
1300+
std::enable_if_t<std::is_convertible_v<U, T>> * = nullptr,
1301+
expected_detail::enable_forward_t<T, E, U> * = nullptr>
12901302
constexpr expected(U &&v) noexcept(std::is_nothrow_constructible_v<T, U>)
12911303
: expected(std::in_place, std::forward<U>(v))
12921304
{
12931305
}
12941306

12951307
// explicit
12961308
template<
1297-
class U = T,
1309+
class U = std::remove_cv_t<T>,
12981310
std::enable_if_t<!std::is_convertible_v<U, T>> * = nullptr,
12991311
expected_detail::enable_forward_t<T, E, U> * = nullptr>
13001312
constexpr explicit expected(U &&v) noexcept(std::is_nothrow_constructible_v<T, U>)
@@ -1418,7 +1430,7 @@ class expected
14181430
// assignments
14191431

14201432
template<
1421-
class U = T, //
1433+
class U = std::remove_cv_t<T>,
14221434
std::enable_if_t< //
14231435
!std::is_same_v<expected, expected_detail::remove_cvref_t<U>> && //
14241436
!expected_detail::is_specialization_v<expected_detail::remove_cvref_t<U>, unexpected> && //
@@ -1544,14 +1556,15 @@ class expected
15441556
}
15451557

15461558
template<class OT = T, class OE = E>
1547-
constexpr
1548-
std::enable_if_t<
1559+
constexpr std::enable_if_t<
15491560
std::is_swappable_v<OT> && std::is_swappable_v<OE> && //
15501561
std::is_move_constructible_v<OT> && std::is_move_constructible_v<OE> && //
15511562
(std::is_nothrow_move_constructible_v<OT> || std::is_nothrow_move_constructible_v<OE>)>
15521563
swap(expected &rhs) //
1553-
noexcept(std::is_nothrow_move_constructible_v<T> && std::is_nothrow_swappable_v<T> && //
1554-
std::is_nothrow_move_constructible_v<E> && std::is_nothrow_swappable_v<E>)
1564+
noexcept(
1565+
std::is_nothrow_move_constructible_v<T> && std::is_nothrow_swappable_v<T> && //
1566+
std::is_nothrow_move_constructible_v<E> && std::is_nothrow_swappable_v<E>
1567+
)
15551568
{
15561569
using std::swap;
15571570
if (this->m_has_val && rhs.m_has_val)
@@ -1688,7 +1701,7 @@ class expected
16881701
return std::move(err());
16891702
}
16901703

1691-
template<class U>
1704+
template<class U = std::remove_cv_t<T>>
16921705
constexpr T value_or(U &&v) const & //
16931706
noexcept(std::is_nothrow_copy_constructible_v<T> && expected_detail::is_nothrow_convertible_v<U, T>)
16941707
{
@@ -1703,7 +1716,7 @@ class expected
17031716
return static_cast<T>(std::forward<U>(v));
17041717
}
17051718
}
1706-
template<class U>
1719+
template<class U = std::remove_cv_t<T>>
17071720
constexpr T value_or(U &&v) && //
17081721
noexcept(std::is_nothrow_move_constructible_v<T> && expected_detail::is_nothrow_convertible_v<U, T>)
17091722
{
@@ -2143,6 +2156,9 @@ class expected<void, E>
21432156
typedef E error_type;
21442157
typedef unexpected<E> unexpected_type;
21452158

2159+
template<class U>
2160+
using rebind = expected<U, error_type>;
2161+
21462162
constexpr expected() = default;
21472163
constexpr expected(const expected &rhs) = default;
21482164
constexpr expected(expected &&rhs) = default;

tests/test_expected/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set(SOURCES
55
monadic_tests.cpp
66
noexcept_tests.cpp
77
equality_tests.cpp
8+
lwg_3886_tests.cpp
89
test_expected_main.cpp
910
)
1011

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#include <catch2/catch_all.hpp>
2+
3+
#include <zeus/expected.hpp>
4+
5+
using namespace zeus;
6+
7+
namespace
8+
{
9+
10+
struct ConstructModeDistinction
11+
{
12+
enum ConstructedMode
13+
{
14+
kDefault,
15+
kCopy,
16+
kMove,
17+
kCopyAssign,
18+
kMoveAssign,
19+
};
20+
21+
constexpr ConstructModeDistinction() noexcept
22+
: mode(kDefault)
23+
{
24+
}
25+
constexpr ConstructModeDistinction(ConstructModeDistinction const&) noexcept
26+
: mode(kCopy)
27+
{
28+
}
29+
constexpr ConstructModeDistinction(ConstructModeDistinction&&) noexcept
30+
: mode(kMove)
31+
{
32+
}
33+
constexpr ConstructModeDistinction& operator=(ConstructModeDistinction&&) noexcept
34+
{
35+
mode = kMoveAssign;
36+
return *this;
37+
}
38+
constexpr ConstructModeDistinction& operator=(ConstructModeDistinction const&) noexcept
39+
{
40+
mode = kCopyAssign;
41+
return *this;
42+
}
43+
44+
ConstructedMode mode;
45+
};
46+
47+
} // namespace
48+
49+
SCENARIO("Monad mo' problems", "[LWG-3886]")
50+
{
51+
using T = const ConstructModeDistinction;
52+
using E = int;
53+
54+
// FIXME LWG-3891
55+
//SECTION("constructor")
56+
//{
57+
// expected<T, E> const e({});
58+
// CHECK(e.value().mode == T::kMove);
59+
//}
60+
//SECTION("assignment")
61+
//{
62+
// expected<T, E> e {zeus::unexpect};
63+
// e = {};
64+
// CHECK(e.value().mode == T::kMove);
65+
//}
66+
67+
SECTION("value_or()")
68+
{
69+
expected<T, E> const e {zeus::unexpect};
70+
CHECK(e.value_or({}).mode == T::kMove);
71+
}
72+
}

tests/third_party/msvc/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
include_directories(SYSTEM "include")
2+
13
add_subdirectory(msvc_stl_p0323r12_test)
24
if (MSVC_TOOLSET_VERSION GREATER_EQUAL 143)
35
# can only built with v143 and later
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
#pragma once
5+
6+
#include <yvals_core.h>
7+
8+
namespace detail {
9+
constexpr bool permissive() {
10+
return false;
11+
}
12+
13+
template <class>
14+
struct PermissiveTestBase {
15+
static constexpr bool permissive() {
16+
return true;
17+
}
18+
};
19+
20+
template <class T>
21+
struct PermissiveTest : PermissiveTestBase<T> {
22+
static constexpr bool test() {
23+
return permissive();
24+
}
25+
};
26+
} // namespace detail
27+
28+
template <class T>
29+
constexpr bool is_permissive_v = detail::PermissiveTest<T>::test();
30+
31+
_INLINE_VAR constexpr bool is_permissive = is_permissive_v<int>;

0 commit comments

Comments
 (0)