//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // // template constexpr auto and_then(F&& f) &; // template constexpr auto and_then(F&& f) const &; // template constexpr auto and_then(F&& f) &&; // template constexpr auto and_then(F&& f) const &&; #include #include #include #include #include #include struct NonCopyable { constexpr NonCopyable(int) {} NonCopyable(const NonCopyable&) = delete; }; struct NonMovable { constexpr NonMovable(int) {} NonMovable(NonMovable&&) = delete; }; template concept has_and_then = requires(E&& e, F&& f) { { std::forward(e).and_then(std::forward(f)) }; }; std::expected return_int() { return {}; } std::expected return_noncopyable() { return {}; } std::expected return_nonmovable() { return {}; } static_assert(has_and_then&, decltype(return_int)>); static_assert(!has_and_then&, decltype(return_noncopyable)>); static_assert(has_and_then&, decltype(return_int)>); static_assert(!has_and_then&, decltype(return_noncopyable)>); static_assert(has_and_then&&, decltype(return_int)>); static_assert(!has_and_then&&, decltype(return_nonmovable)>); static_assert(has_and_then&&, decltype(return_int)>); static_assert(!has_and_then&&, decltype(return_nonmovable)>); // [LWG 3877] https://cplusplus.github.io/LWG/issue3877, check constraint failing but not compile error inside the function body. static_assert(!has_and_then>&, int()>); static_assert(!has_and_then>&&, int()>); constexpr void test_val_types() { // Test & overload { auto l = []() -> std::expected { return 2; }; std::expected v; std::same_as> decltype(auto) val = v.and_then(l); assert(val == 2); } // Test const& overload { auto l = []() -> std::expected { return 2; }; const std::expected v; assert(v.and_then(l).value() == 2); static_assert(std::is_same_v< decltype(v.and_then(l)), std::expected>); } // Test && overload { auto l = []() -> std::expected { return 2; }; std::expected v; std::same_as> decltype(auto) val = std::move(v).and_then(l); assert(val == 2); } // Test const&& overload { auto l = []() -> std::expected { return 2; }; const std::expected v; std::same_as> decltype(auto) val = std::move(v).and_then(l); assert(val == 2); } } constexpr void test_fail() { // Test & overload { auto f = []() -> std::expected { assert(false); return 0; }; std::expected v(std::unexpected(2)); std::same_as> decltype(auto) val = v.and_then(f); assert(val.error() == 2); } // Test const& overload { auto f = []() -> std::expected { assert(false); return 0; }; const std::expected v(std::unexpected(2)); std::same_as> decltype(auto) val = v.and_then(f); assert(val.error() == 2); } // Test && overload { auto f = []() -> std::expected { assert(false); return 0; }; std::expected v(std::unexpected(2)); std::same_as> decltype(auto) val = std::move(v).and_then(f); assert(val.error() == 2); } // Test const&& overload { auto f = []() -> std::expected { assert(false); return 0; }; const std::expected v(std::unexpected(2)); std::same_as> decltype(auto) val = std::move(v).and_then(f); assert(val.error() == 2); } } constexpr bool test() { test_fail(); test_val_types(); return true; } int main(int, char**) { test(); static_assert(test()); return 0; }