| // { dg-do run { target c++23 } } |
| |
| #include <optional> |
| #include <testsuite_hooks.h> |
| |
| constexpr bool |
| test_transform() |
| { |
| std::optional<int> o; |
| auto&& r = o.transform([](int) -> unsigned { throw 1; }); |
| static_assert( std::is_same_v<decltype(r), std::optional<unsigned>&&> ); |
| VERIFY( ! r.has_value() ); |
| |
| o = 10; |
| auto&& r2 = o.transform([](int i) -> unsigned { return i + 2u; }); |
| static_assert( std::is_same_v<decltype(r2), std::optional<unsigned>&&> ); |
| VERIFY( *r2 == 12u ); |
| |
| return true; |
| } |
| |
| static_assert( test_transform() ); |
| |
| enum { CalledLvalue = 1, CalledConst = 2, PassedLvalue = 4, PassedConst = 8 }; |
| |
| struct F |
| { |
| template<typename This, typename Value> |
| static constexpr int |
| called_as() |
| { |
| int res = 0; |
| if constexpr (std::is_lvalue_reference_v<This>) |
| res |= CalledLvalue; |
| if constexpr (std::is_const_v<std::remove_reference_t<This>>) |
| res |= CalledConst; |
| |
| if constexpr (std::is_lvalue_reference_v<Value>) |
| res |= PassedLvalue; |
| if constexpr (std::is_const_v<std::remove_reference_t<Value>>) |
| res |= PassedConst; |
| |
| return res; |
| } |
| |
| template<typename T> |
| constexpr int |
| operator()(T&&) & |
| { return called_as<F&, T>(); } |
| |
| template<typename T> |
| constexpr int |
| operator()(T&&) const & |
| { return called_as<const F&, T>(); } |
| |
| template<typename T> |
| constexpr int |
| operator()(T&&) && |
| { return called_as<F, T>(); } |
| |
| template<typename T> |
| constexpr int |
| operator()(T&&) const && |
| { return called_as<const F, T>(); } |
| }; |
| |
| constexpr bool |
| test_forwarding() |
| { |
| std::optional<long> o = 1; |
| F f; |
| |
| VERIFY( *o.transform(f) == (PassedLvalue|CalledLvalue) ); |
| VERIFY( *o.transform(std::move(f)) == PassedLvalue ); |
| VERIFY( *std::move(o).transform(f) == CalledLvalue ); |
| VERIFY( *std::move(o).transform(std::move(f)) == 0 ); |
| |
| const auto& co = o; |
| |
| VERIFY( *co.transform(f) == (PassedLvalue|PassedConst|CalledLvalue) ); |
| VERIFY( *co.transform(std::move(f)) == (PassedLvalue|PassedConst) ); |
| VERIFY( *std::move(co).transform(f) == (PassedConst|CalledLvalue) ); |
| VERIFY( *std::move(co).transform(std::move(f)) == PassedConst ); |
| |
| const auto& cf = f; |
| |
| VERIFY( *o.transform(cf) == (PassedLvalue|CalledLvalue|CalledConst) ); |
| VERIFY( *o.transform(std::move(cf)) == (PassedLvalue|CalledConst) ); |
| VERIFY( *std::move(o).transform(cf) == (CalledLvalue|CalledConst) ); |
| VERIFY( *std::move(o).transform(std::move(cf)) == CalledConst ); |
| |
| VERIFY( *co.transform(cf) == (PassedLvalue|PassedConst|CalledLvalue|CalledConst) ); |
| VERIFY( *co.transform(std::move(cf)) == (PassedLvalue|PassedConst|CalledConst) ); |
| VERIFY( *std::move(co).transform(cf) == (PassedConst|CalledLvalue|CalledConst) ); |
| VERIFY( *std::move(co).transform(std::move(cf)) == (PassedConst|CalledConst) ); |
| |
| o = std::nullopt; |
| |
| VERIFY( ! o.transform(f).has_value() ); |
| VERIFY( ! co.transform(f).has_value() ); |
| VERIFY( ! std::move(o).transform(f).has_value() ); |
| VERIFY( ! std::move(co).transform(f).has_value() ); |
| |
| return true; |
| } |
| |
| static_assert( test_forwarding() ); |
| |
| constexpr bool |
| test_copy_elision() |
| { |
| struct immovable |
| { |
| constexpr immovable(int p) : power_level(p) { } |
| immovable(immovable&&) = delete; |
| |
| int power_level; |
| }; |
| |
| struct Force |
| { |
| constexpr immovable operator()(int i) const { return {i+1}; } |
| }; |
| |
| std::optional<int> irresistible(9000); |
| std::optional<immovable> object = irresistible.transform(Force{}); |
| VERIFY( object->power_level > 9000 ); |
| |
| return true; |
| } |
| |
| static_assert( test_copy_elision() ); |
| |
| void f(int&) { } |
| |
| void |
| test_unconstrained() |
| { |
| // PR libstdc++/102863 - Optional monadic ops should not be constrained |
| std::optional<int> x; |
| auto answer = x.transform([](auto& y) { f(y); return 42; }); |
| VERIFY( !answer ); |
| } |
| |
| int main() |
| { |
| test_transform(); |
| test_forwarding(); |
| test_copy_elision(); |
| test_unconstrained(); |
| } |