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 {
NonCopyableNonCopyable26   constexpr NonCopyable(int) {}
27   NonCopyable(const NonCopyable&) = delete;
28 };
29 
30 struct NonMovable {
NonMovableNonMovable31   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 
return_int()41 std::expected<void, int> return_int() { return {}; }
return_noncopyable()42 std::expected<void, NonCopyable> return_noncopyable() { return {}; }
return_nonmovable()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 
test_val_types()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 
test_fail()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 
test()138 constexpr bool test() {
139   test_fail();
140   test_val_types();
141   return true;
142 }
143 
main(int,char **)144 int main(int, char**) {
145   test();
146   static_assert(test());
147 
148   return 0;
149 }
150