1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 |
10 | |
11 | // <expected> |
12 | |
13 | // template<class F> constexpr auto and_then(F&& f) &; |
14 | // template<class F> constexpr auto and_then(F&& f) const &; |
15 | // template<class F> constexpr auto and_then(F&& f) &&; |
16 | // template<class F> constexpr auto and_then(F&& f) const &&; |
17 | |
18 | #include <expected> |
19 | #include <concepts> |
20 | #include <cassert> |
21 | #include <memory> |
22 | #include <type_traits> |
23 | #include <utility> |
24 | |
25 | struct NonCopyable { |
26 | constexpr NonCopyable(int) {} |
27 | NonCopyable(const NonCopyable&) = delete; |
28 | }; |
29 | |
30 | struct NonMovable { |
31 | constexpr NonMovable(int) {} |
32 | NonMovable(NonMovable&&) = delete; |
33 | }; |
34 | |
35 | template <class E, class F> |
36 | concept has_and_then = |
37 | requires(E&& e, F&& f) { |
38 | { std::forward<E>(e).and_then(std::forward<F>(f)) }; |
39 | }; |
40 | |
41 | std::expected<void, int> return_int() { return {}; } |
42 | std::expected<void, NonCopyable> return_noncopyable() { return {}; } |
43 | std::expected<void, NonMovable> return_nonmovable() { return {}; } |
44 | |
45 | static_assert(has_and_then<std::expected<void, int>&, decltype(return_int)>); |
46 | static_assert(!has_and_then<std::expected<void, NonCopyable>&, decltype(return_noncopyable)>); |
47 | static_assert(has_and_then<const std::expected<void, int>&, decltype(return_int)>); |
48 | static_assert(!has_and_then<const std::expected<void, NonCopyable>&, decltype(return_noncopyable)>); |
49 | static_assert(has_and_then<std::expected<void, int>&&, decltype(return_int)>); |
50 | static_assert(!has_and_then<std::expected<void, NonMovable>&&, decltype(return_nonmovable)>); |
51 | static_assert(has_and_then<const std::expected<void, int>&&, decltype(return_int)>); |
52 | static_assert(!has_and_then<const std::expected<void, NonMovable>&&, decltype(return_nonmovable)>); |
53 | |
54 | // [LWG 3877] https://cplusplus.github.io/LWG/issue3877, check constraint failing but not compile error inside the function body. |
55 | static_assert(!has_and_then<const std::expected<int, std::unique_ptr<int>>&, int()>); |
56 | static_assert(!has_and_then<const std::expected<int, std::unique_ptr<int>>&&, int()>); |
57 | |
58 | constexpr void test_val_types() { |
59 | // Test & overload |
60 | { |
61 | auto l = []() -> std::expected<int, int> { return 2; }; |
62 | std::expected<void, int> v; |
63 | std::same_as<std::expected<int, int>> decltype(auto) val = v.and_then(l); |
64 | assert(val == 2); |
65 | } |
66 | |
67 | // Test const& overload |
68 | { |
69 | auto l = []() -> std::expected<int, int> { return 2; }; |
70 | const std::expected<void, int> v; |
71 | assert(v.and_then(l).value() == 2); |
72 | static_assert(std::is_same_v< decltype(v.and_then(l)), std::expected<int, int>>); |
73 | } |
74 | |
75 | // Test && overload |
76 | { |
77 | auto l = []() -> std::expected<int, int> { return 2; }; |
78 | std::expected<void, int> v; |
79 | std::same_as<std::expected<int, int>> decltype(auto) val = std::move(v).and_then(l); |
80 | assert(val == 2); |
81 | } |
82 | |
83 | // Test const&& overload |
84 | { |
85 | auto l = []() -> std::expected<int, int> { return 2; }; |
86 | const std::expected<void, int> v; |
87 | std::same_as<std::expected<int, int>> decltype(auto) val = std::move(v).and_then(l); |
88 | assert(val == 2); |
89 | } |
90 | } |
91 | |
92 | constexpr void test_fail() { |
93 | // Test & overload |
94 | { |
95 | auto f = []() -> std::expected<int, int> { |
96 | assert(false); |
97 | return 0; |
98 | }; |
99 | std::expected<void, int> v(std::unexpected<int>(2)); |
100 | std::same_as<std::expected<int, int>> decltype(auto) val = v.and_then(f); |
101 | assert(val.error() == 2); |
102 | } |
103 | |
104 | // Test const& overload |
105 | { |
106 | auto f = []() -> std::expected<int, int> { |
107 | assert(false); |
108 | return 0; |
109 | }; |
110 | const std::expected<void, int> v(std::unexpected<int>(2)); |
111 | std::same_as<std::expected<int, int>> decltype(auto) val = v.and_then(f); |
112 | assert(val.error() == 2); |
113 | } |
114 | |
115 | // Test && overload |
116 | { |
117 | auto f = []() -> std::expected<int, int> { |
118 | assert(false); |
119 | return 0; |
120 | }; |
121 | std::expected<void, int> v(std::unexpected<int>(2)); |
122 | std::same_as<std::expected<int, int>> decltype(auto) val = std::move(v).and_then(f); |
123 | assert(val.error() == 2); |
124 | } |
125 | |
126 | // Test const&& overload |
127 | { |
128 | auto f = []() -> std::expected<int, int> { |
129 | assert(false); |
130 | return 0; |
131 | }; |
132 | const std::expected<void, int> v(std::unexpected<int>(2)); |
133 | std::same_as<std::expected<int, int>> decltype(auto) val = std::move(v).and_then(f); |
134 | assert(val.error() == 2); |
135 | } |
136 | } |
137 | |
138 | constexpr bool test() { |
139 | test_fail(); |
140 | test_val_types(); |
141 | return true; |
142 | } |
143 | |
144 | int main(int, char**) { |
145 | test(); |
146 | static_assert(test()); |
147 | |
148 | return 0; |
149 | } |
150 | |