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 // GCC has a issue for `Guaranteed copy elision for potentially-overlapping non-static data members`, 12 // please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333, but we have a workaround to 13 // avoid this issue. 14 15 // <expected> 16 17 // template<class F> constexpr auto transform(F&& f) &; 18 // template<class F> constexpr auto transform(F&& f) const &; 19 // template<class F> constexpr auto transform(F&& f) &&; 20 // template<class F> constexpr auto transform(F&& f) const &&; 21 22 #include <expected> 23 #include <concepts> 24 #include <cassert> 25 #include <memory> 26 #include <type_traits> 27 #include <utility> 28 29 struct LVal { 30 constexpr int operator()(int&) { return 1; } 31 int operator()(const int&) = delete; 32 int operator()(int&&) = delete; 33 int operator()(const int&&) = delete; 34 }; 35 36 struct CLVal { 37 int operator()(int&) = delete; 38 constexpr int operator()(const int&) { return 1; } 39 int operator()(int&&) = delete; 40 int operator()(const int&&) = delete; 41 }; 42 43 struct RVal { 44 int operator()(int&) = delete; 45 int operator()(const int&) = delete; 46 constexpr int operator()(int&&) { return 1; } 47 int operator()(const int&&) = delete; 48 }; 49 50 struct CRVal { 51 int operator()(int&) = delete; 52 int operator()(const int&) = delete; 53 int operator()(int&&) = delete; 54 constexpr int operator()(const int&&) { return 1; } 55 }; 56 57 struct RefQual { 58 constexpr int operator()(int) & { return 1; } 59 int operator()(int) const& = delete; 60 int operator()(int) && = delete; 61 int operator()(int) const&& = delete; 62 }; 63 64 struct CRefQual { 65 int operator()(int) & = delete; 66 constexpr int operator()(int) const& { return 1; } 67 int operator()(int) && = delete; 68 int operator()(int) const&& = delete; 69 }; 70 71 struct RVRefQual { 72 int operator()(int) & = delete; 73 int operator()(int) const& = delete; 74 constexpr int operator()(int) && { return 1; } 75 int operator()(int) const&& = delete; 76 }; 77 78 struct RVCRefQual { 79 int operator()(int) & = delete; 80 int operator()(int) const& = delete; 81 int operator()(int) && = delete; 82 constexpr int operator()(int) const&& { return 1; } 83 }; 84 85 struct NonCopy { 86 int value; 87 constexpr explicit NonCopy(int val) : value(val) {} 88 NonCopy(const NonCopy&) = delete; 89 }; 90 91 struct NonConst { 92 int non_const() { return 1; } 93 }; 94 95 template <class E, class F> 96 concept has_transform = 97 requires(E&& e, F&& f) { 98 { std::forward<E>(e).transform(std::forward<F>(f)) }; 99 }; 100 101 // [LWG 3877] https://cplusplus.github.io/LWG/issue3877, check constraint failing but not compile error inside the function body. 102 static_assert(!has_transform<const std::expected<int, std::unique_ptr<int>>&, int()>); 103 static_assert(!has_transform<const std::expected<int, std::unique_ptr<int>>&&, int()>); 104 105 // clang-format off 106 constexpr void test_val_types() { 107 // Test & overload 108 { 109 // Without &qualifier on F'soperator() 110 { 111 std::expected<int, int> e(0); 112 std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(LVal{}); 113 assert(val == 1); 114 } 115 116 // With & qualifier on F's operator() 117 { 118 std::expected<int, int> e(0); 119 RefQual l{}; 120 std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(l); 121 assert(val == 1); 122 } 123 } 124 125 // Test const& overload 126 { 127 // Without & qualifier on F's operator() 128 { 129 const std::expected<int, int> e(0); 130 std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(CLVal{}); 131 assert(val == 1); 132 } 133 134 // With & qualifier on F's operator() 135 { 136 const std::expected<int, int> e(0); 137 const CRefQual l{}; 138 std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(l); 139 assert(val == 1); 140 } 141 } 142 143 // Test && overload 144 { 145 // Without & qualifier on F's operator() 146 { 147 std::expected<int, int> e(0); 148 std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).transform(RVal{}); 149 assert(val == 1); 150 } 151 152 // With & qualifier on F's operator() 153 { 154 std::expected<int, int> e(0); 155 std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).transform(RVRefQual{}); 156 assert(val == 1); 157 } 158 } 159 160 // Test const&& overload 161 { 162 // Without & qualifier on F's operator() 163 { 164 const std::expected<int, int> e(0); 165 std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).transform(CRVal{}); 166 assert(val == 1); 167 } 168 169 // With & qualifier on F's operator() 170 { 171 const std::expected<int, int> e(0); 172 const RVCRefQual l{}; 173 std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(std::move(l)); 174 assert(val == 1); 175 } 176 } 177 } 178 // clang-format on 179 180 constexpr void test_take_val_return_void() { 181 std::expected<int, int> e(1); 182 int val = 0; 183 e.transform([&val]<typename T>(T&&) -> void { 184 static_assert(std::is_same_v<T, int&>); 185 assert(val == 0); 186 val = 1; 187 }); 188 assert(val == 1); 189 std::move(e).transform([&val]<typename T>(T&&) -> void { 190 static_assert(std::is_same_v<T, int>); 191 assert(val == 1); 192 val = 2; 193 }); 194 195 const auto& ce = e; 196 assert(val == 2); 197 ce.transform([&val]<typename T>(T&&) -> void { 198 static_assert(std::is_same_v<T, const int&>); 199 assert(val == 2); 200 val = 3; 201 }); 202 assert(val == 3); 203 std::move(ce).transform([&val]<typename T>(T&&) -> void { 204 static_assert(std::is_same_v<T, const int>); 205 assert(val == 3); 206 val = 4; 207 }); 208 assert(val == 4); 209 } 210 211 // check val member is direct-non-list-initialized with invoke(std::forward<F>(f), value()) 212 constexpr void test_direct_non_list_init() { 213 auto xform = [](int i) { return NonCopy(i); }; 214 std::expected<int, int> e(2); 215 std::expected<NonCopy, int> n = e.transform(xform); 216 assert(n.value().value == 2); 217 } 218 219 // check that the lambda body is not instantiated during overload resolution 220 constexpr void test_sfinae() { 221 std::expected<NonConst, int> e(std::unexpected<int>(2)); 222 auto l = [](auto&& x) { return x.non_const(); }; 223 e.transform(l); 224 std::move(e).transform(l); 225 226 std::expected<int, int> e1(std::unexpected<int>(1)); 227 const auto& ce1 = e1; 228 const auto never_called = [](int) { 229 assert(false); 230 return std::expected<int, int>(); 231 }; 232 233 e1.transform(never_called); 234 std::move(e1).transform(never_called); 235 ce1.and_then(never_called); 236 std::move(ce1).transform(never_called); 237 } 238 239 constexpr bool test() { 240 test_sfinae(); 241 test_val_types(); 242 test_direct_non_list_init(); 243 return true; 244 } 245 246 int main(int, char**) { 247 test(); 248 static_assert(test()); 249 250 return 0; 251 } 252