diff --git a/proxy.h b/proxy.h index 4004ca8..f947804 100644 --- a/proxy.h +++ b/proxy.h @@ -90,11 +90,20 @@ consteval bool has_destructibility(constraint_level level) { // As per std::to_address() wording in [pointer.conversion] template -concept is_address_deducible = - (std::is_pointer_v

&& !std::is_function_v>) || +concept is_address_deducible = std::is_pointer_v

|| requires(P p) { std::pointer_traits

::to_address(p); } || requires(P p) { p.operator->(); }; +// Bypass function pointer restriction of std::to_address() +template +auto deduce_address(const P& p) { + if constexpr (std::is_pointer_v

) { + return p; + } else { + return std::to_address(p); + } +} + template struct contains_traits : inapplicable_traits {}; template struct contains_traits : applicable_traits {}; @@ -130,14 +139,14 @@ struct overload_traits : applicable_traits { template static constexpr bool applicable_pointer = requires(const P& p, Args... args) - { { D{}(*std::to_address(p), std::forward(args)...) }; }; + { D{}(*deduce_address(p), std::forward(args)...); }; template static R dispatcher(const char* erased, Args... args) { const P& p = *reinterpret_cast(erased); if constexpr (std::is_void_v) { - D{}(*std::to_address(p), std::forward(args)...); + D{}(*deduce_address(p), std::forward(args)...); } else { - return D{}(*std::to_address(p), std::forward(args)...); + return D{}(*deduce_address(p), std::forward(args)...); } } }; @@ -180,7 +189,7 @@ struct dispatch_traits_impl> : applicable_traits, template struct dispatch_traits : inapplicable_traits {}; template requires(requires { typename D::overload_types; - { D{} }; + D{}; }) struct dispatch_traits : dispatch_traits_impl {}; @@ -603,7 +612,7 @@ struct facade_prototype { #define PRO_DEF_MEMBER_DISPATCH(__NAME, ...) \ struct __NAME { \ - using overload_types = std::tuple<__VA_ARGS__>;\ + using overload_types = std::tuple<__VA_ARGS__>; \ template \ decltype(auto) operator()(__T&& __self, __Args&&... __args) \ requires(requires{ std::forward<__T>(__self) \ @@ -614,7 +623,7 @@ struct facade_prototype { } #define PRO_DEF_FREE_DISPATCH(__NAME, __FUNC, ...) \ struct __NAME { \ - using overload_types = std::tuple<__VA_ARGS__>;\ + using overload_types = std::tuple<__VA_ARGS__>; \ template \ decltype(auto) operator()(__T&& __self, __Args&&... __args) \ requires(requires{ __FUNC(std::forward<__T>(__self), \ diff --git a/tests/proxy_invocation_tests.cpp b/tests/proxy_invocation_tests.cpp index 106d9c5..99cea48 100644 --- a/tests/proxy_invocation_tests.cpp +++ b/tests/proxy_invocation_tests.cpp @@ -43,7 +43,6 @@ struct Append { } // namespace poly - template concept InvocableWithDispatch = requires(pro::proxy p, Args... args) { { p.template invoke(std::forward(args)...) }; }; @@ -163,3 +162,10 @@ TEST(ProxyInvocationTests, TestOverloadResolution) { ASSERT_EQ(side_effect, (GetTypeIndices())); ASSERT_FALSE((std::is_invocable_v>)); } + +TEST(ProxyInvocationTests, TestFunctionPointer) { + struct TestFacade : poly::Callable()> {}; + pro::proxy p{ &GetTypeIndices }; + auto ret = p(); + ASSERT_EQ(ret, (GetTypeIndices())); +} diff --git a/tests/proxy_traits_tests.cpp b/tests/proxy_traits_tests.cpp index 41daddd..4a34658 100644 --- a/tests/proxy_traits_tests.cpp +++ b/tests/proxy_traits_tests.cpp @@ -22,6 +22,7 @@ using MockMovablePtr = MockPtr; using MockCopyableSmallPtr = MockPtr; using MockTrivialPtr = MockPtr; +using MockFunctionPtr = void(*)(); PRO_DEF_FACADE(DefaultFacade); static_assert(DefaultFacade::pointer_constraints.minimum_copyability == pro::constraint_level::none); @@ -39,6 +40,7 @@ static_assert(std::is_nothrow_constructible_v, std::in static_assert(std::is_nothrow_constructible_v, std::in_place_type_t, int>); static_assert(std::is_nothrow_constructible_v, std::in_place_type_t, int>); static_assert(std::is_nothrow_constructible_v, std::in_place_type_t, int>); +static_assert(std::is_nothrow_constructible_v, std::in_place_type_t, MockFunctionPtr>); PRO_DEF_FACADE(RelocatableFacade); static_assert(!std::is_copy_constructible_v>); @@ -55,6 +57,7 @@ static_assert(pro::proxiable); static_assert(pro::proxiable); static_assert(pro::proxiable); static_assert(pro::proxiable); +static_assert(pro::proxiable); static_assert(std::is_nothrow_constructible_v, MockMovablePtr>); static_assert(std::is_nothrow_assignable_v, MockMovablePtr>); static_assert(std::is_nothrow_constructible_v, MockCopyablePtr>); @@ -63,6 +66,8 @@ static_assert(std::is_nothrow_constructible_v, Moc static_assert(std::is_nothrow_assignable_v, MockCopyableSmallPtr>); static_assert(std::is_nothrow_constructible_v, MockTrivialPtr>); static_assert(std::is_nothrow_assignable_v, MockTrivialPtr>); +static_assert(std::is_nothrow_constructible_v, MockFunctionPtr>); +static_assert(std::is_nothrow_assignable_v, MockFunctionPtr>); PRO_DEF_FACADE(CopyableFacade, PRO_MAKE_DISPATCH_PACK(), pro::copyable_pointer_constraints); static_assert(std::is_copy_constructible_v>); @@ -79,6 +84,7 @@ static_assert(!pro::proxiable); static_assert(pro::proxiable); static_assert(pro::proxiable); static_assert(pro::proxiable); +static_assert(pro::proxiable); static_assert(!std::is_constructible_v, MockMovablePtr>); static_assert(!std::is_assignable_v, MockMovablePtr>); static_assert(std::is_nothrow_constructible_v, MockCopyablePtr>); @@ -87,6 +93,8 @@ static_assert(std::is_nothrow_constructible_v, MockCo static_assert(std::is_nothrow_assignable_v, MockCopyableSmallPtr>); static_assert(std::is_nothrow_constructible_v, MockTrivialPtr>); static_assert(std::is_nothrow_assignable_v, MockTrivialPtr>); +static_assert(std::is_nothrow_constructible_v, MockFunctionPtr>); +static_assert(std::is_nothrow_assignable_v, MockFunctionPtr>); PRO_DEF_FACADE(CopyableSmallFacade, PRO_MAKE_DISPATCH_PACK(), pro::proxy_pointer_constraints{ .maximum_size = sizeof(void*), @@ -99,6 +107,7 @@ static_assert(!pro::proxiable); static_assert(!pro::proxiable); static_assert(pro::proxiable); static_assert(pro::proxiable); +static_assert(pro::proxiable); static_assert(!std::is_constructible_v, MockMovablePtr>); static_assert(!std::is_assignable_v, MockMovablePtr>); static_assert(!std::is_constructible_v, MockCopyablePtr>); @@ -107,6 +116,8 @@ static_assert(std::is_nothrow_constructible_v, M static_assert(std::is_nothrow_assignable_v, MockCopyableSmallPtr>); static_assert(std::is_constructible_v, MockTrivialPtr>); static_assert(std::is_assignable_v, MockTrivialPtr>); +static_assert(std::is_constructible_v, MockFunctionPtr>); +static_assert(std::is_assignable_v, MockFunctionPtr>); PRO_DEF_FACADE(TrivialFacade, PRO_MAKE_DISPATCH_PACK(), pro::trivial_pointer_constraints); static_assert(std::is_trivially_copy_constructible_v>); @@ -120,6 +131,7 @@ static_assert(!pro::proxiable); static_assert(!pro::proxiable); static_assert(!pro::proxiable); static_assert(pro::proxiable); +static_assert(pro::proxiable); static_assert(!std::is_constructible_v, MockMovablePtr>); static_assert(!std::is_assignable_v, MockMovablePtr>); static_assert(!std::is_constructible_v, MockCopyablePtr>); @@ -128,5 +140,7 @@ static_assert(!std::is_constructible_v, MockCopyableSm static_assert(!std::is_assignable_v, MockCopyableSmallPtr>); static_assert(std::is_nothrow_constructible_v, MockTrivialPtr>); static_assert(std::is_nothrow_assignable_v, MockTrivialPtr>); +static_assert(std::is_nothrow_constructible_v, MockFunctionPtr>); +static_assert(std::is_nothrow_assignable_v, MockFunctionPtr>); } // namespace