// { dg-options "-std=gnu++23" } // { dg-do run { target c++23 } } // { dg-require-effective-target hosted } #include #include #include using std::move_only_function; using std::is_same_v; using std::is_invocable_v; using std::is_nothrow_invocable_v; using std::invoke_result_t; // Check return types static_assert( is_same_v>> ); static_assert( is_same_v>> ); static_assert( is_same_v>> ); // With const qualifier static_assert( ! is_invocable_v< move_only_function const > ); static_assert( ! is_invocable_v< move_only_function const &> ); static_assert( is_invocable_v< move_only_function > ); static_assert( is_invocable_v< move_only_function &> ); static_assert( is_invocable_v< move_only_function const > ); static_assert( is_invocable_v< move_only_function const &> ); // With no ref-qualifier static_assert( is_invocable_v< move_only_function > ); static_assert( is_invocable_v< move_only_function &> ); static_assert( is_invocable_v< move_only_function > ); static_assert( is_invocable_v< move_only_function &> ); static_assert( is_invocable_v< move_only_function const > ); static_assert( is_invocable_v< move_only_function const &> ); // With & ref-qualifier static_assert( ! is_invocable_v< move_only_function > ); static_assert( is_invocable_v< move_only_function &> ); static_assert( is_invocable_v< move_only_function > ); static_assert( is_invocable_v< move_only_function &> ); static_assert( is_invocable_v< move_only_function const > ); static_assert( is_invocable_v< move_only_function const &> ); // With && ref-qualifier static_assert( is_invocable_v< move_only_function > ); static_assert( ! is_invocable_v< move_only_function &> ); static_assert( is_invocable_v< move_only_function > ); static_assert( ! is_invocable_v< move_only_function &> ); static_assert( is_invocable_v< move_only_function const > ); static_assert( ! is_invocable_v< move_only_function const &> ); // With noexcept-specifier static_assert( ! is_nothrow_invocable_v< move_only_function > ); static_assert( ! is_nothrow_invocable_v< move_only_function > ); static_assert( is_nothrow_invocable_v< move_only_function > ); static_assert( is_nothrow_invocable_v< move_only_function& > ); void test01() { struct F { int operator()() { return 0; } int operator()() const { return 1; } }; move_only_function f0{F{}}; VERIFY( f0() == 0 ); VERIFY( std::move(f0)() == 0 ); move_only_function f1{F{}}; VERIFY( f1() == 1 ); VERIFY( std::as_const(f1)() == 1 ); VERIFY( std::move(f1)() == 1 ); VERIFY( std::move(std::as_const(f1))() == 1 ); move_only_function f2{F{}}; VERIFY( f2() == 0 ); // Not rvalue-callable: std::move(f2)() move_only_function f3{F{}}; VERIFY( f3() == 1 ); VERIFY( std::as_const(f3)() == 1 ); VERIFY( std::move(f3)() == 1 ); VERIFY( std::move(std::as_const(f3))() == 1 ); move_only_function f4{F{}}; // Not lvalue-callable: f4() VERIFY( std::move(f4)() == 0 ); move_only_function f5{F{}}; // Not lvalue-callable: f5() VERIFY( std::move(f5)() == 1 ); VERIFY( std::move(std::as_const(f5))() == 1 ); } void test02() { struct F { int operator()() & { return 0; } int operator()() && { return 1; } }; move_only_function f0{F{}}; VERIFY( f0() == 0 ); VERIFY( std::move(f0)() == 0 ); move_only_function f1{F{}}; // Not lvalue callable: f1() VERIFY( std::move(f1)() == 1 ); move_only_function f2{F{}}; VERIFY( f2() == 0 ); // Not rvalue-callable: std::move(f2)() } void test03() { struct F { int operator()() const & { return 0; } int operator()() && { return 1; } }; move_only_function f0{F{}}; VERIFY( f0() == 0 ); VERIFY( std::move(f0)() == 0 ); move_only_function f1{F{}}; // Not lvalue callable: f1() VERIFY( std::move(f1)() == 1 ); move_only_function f2{F{}}; VERIFY( f2() == 0 ); VERIFY( std::as_const(f2)() == 0 ); VERIFY( std::move(f2)() == 0 ); VERIFY( std::move(std::as_const(f2))() == 0 ); move_only_function f3{F{}}; // Not lvalue callable: f3() VERIFY( std::move(f3)() == 0 ); VERIFY( std::move(std::as_const(f3))() == 0 ); move_only_function f4{F{}}; VERIFY( f4() == 0 ); VERIFY( std::as_const(f4)() == 0 ); // Not rvalue-callable: std::move(f4)() } void test04() { struct F { int operator()() & { return 0; } int operator()() && { return 1; } int operator()() const & { return 2; } int operator()() const && { return 3; } }; move_only_function f0{F{}}; VERIFY( f0() == 0 ); VERIFY( std::move(f0)() == 0 ); move_only_function f1{F{}}; VERIFY( f1() == 0 ); // Not rvalue-callable: std::move(f1)() move_only_function f2{F{}}; // Not lvalue callable: f2() VERIFY( std::move(f2)() == 1 ); move_only_function f3{F{}}; VERIFY( f3() == 2 ); VERIFY( std::as_const(f3)() == 2 ); VERIFY( std::move(f3)() == 2 ); VERIFY( std::move(std::as_const(f3))() == 2 ); move_only_function f4{F{}}; VERIFY( f4() == 2 ); VERIFY( std::as_const(f4)() == 2 ); // Not rvalue-callable: std::move(f4)() move_only_function f5{F{}}; // Not lvalue callable: f5() VERIFY( std::move(f5)() == 3 ); VERIFY( std::move(std::as_const(f5))() == 3 ); } struct Incomplete; void test_params() { std::move_only_function f1; std::move_only_function f2; std::move_only_function f3; } int main() { test01(); test02(); test03(); test04(); test_params(); }