__invoke_impl - - Dereference the pointer
Frederick Virchanza Gotham
cauldwell.thomas@gmail.com
Mon Jan 19 16:04:55 GMT 2026
On Mon, Jan 19, 2026 at 1:13 PM Tomasz Kaminski wrote:
>
> The current implementation of std::invoke(f, t) support situation when t is
> smart_pointer (shared_ptr, unique_ptr, but also anything with operator*),
> and this is required per standard.
>
> As none of standard defined smart pointers (and I except user defined ones)
> overloads operator->*, your proposed alternative will break their support,
> and be non-confiroming.
Thanks for that.
Here's what I'm thinking is best to do, always try to use "->*" but
fall back to using "(* ).*, as follows:
diff --git a/libstdc++-v3/include/bits/invoke.h
b/libstdc++-v3/include/bits/invoke.h
index 4e000d56e03..4e2c1f5217a 100644
--- a/libstdc++-v3/include/bits/invoke.h
+++ b/libstdc++-v3/include/bits/invoke.h
@@ -68,12 +68,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_Args&&... __args)
{ return (__invfwd<_Tp>(__t).*__f)(std::forward<_Args>(__args)...); }
+ // Helper: preferred overload if (t->*f)(args...) is well-formed
+ template<typename _MemFun, typename _Tp, typename... _Args>
+ auto
+ __invoke_memfun_deref_try(int, _MemFun&& __f, _Tp&& __t, _Args&&... __args)
+ -> decltype( (std::forward<_Tp>(__t)->*std::forward<_MemFun>(__f))
+ (std::forward<_Args>(__args)...) )
+ {
+ return (std::forward<_Tp>(__t)->*std::forward<_MemFun>(__f))
+ (std::forward<_Args>(__args)...);
+ }
+
+ // Fallback overload if the above is ill-formed
+ template<typename _MemFun, typename _Tp, typename... _Args>
+ auto
+ __invoke_memfun_deref_try(long, _MemFun&& __f, _Tp&& __t,
_Args&&... __args)
+ -> decltype( ((*std::forward<_Tp>(__t)).*std::forward<_MemFun>(__f))
+ (std::forward<_Args>(__args)...) )
+ {
+ return ((*std::forward<_Tp>(__t)).*std::forward<_MemFun>(__f))
+ (std::forward<_Args>(__args)...);
+ }
+
template<typename _Res, typename _MemFun, typename _Tp, typename... _Args>
- constexpr _Res
- __invoke_impl(__invoke_memfun_deref, _MemFun&& __f, _Tp&& __t,
- _Args&&... __args)
+ constexpr _Res
+ __invoke_impl(__invoke_memfun_deref, _MemFun&& __f, _Tp&& __t,
_Args&&... __args)
{
- return ((*std::forward<_Tp>(__t)).*__f)(std::forward<_Args>(__args)...);
+ // int preferred, long fallback
+ return __invoke_memfun_deref_try(0,
+ std::forward<_MemFun>(__f),
+ std::forward<_Tp>(__t),
+ std::forward<_Args>(__args)...);
}
template<typename _Res, typename _MemPtr, typename _Tp>
@@ -81,10 +106,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__invoke_impl(__invoke_memobj_ref, _MemPtr&& __f, _Tp&& __t)
{ return __invfwd<_Tp>(__t).*__f; }
- template<typename _Res, typename _MemPtr, typename _Tp>
- constexpr _Res
- __invoke_impl(__invoke_memobj_deref, _MemPtr&& __f, _Tp&& __t)
- { return (*std::forward<_Tp>(__t)).*__f; }
+ // Helper: preferred overload if (t->*f) is well-formed
+ template<typename _MemFun, typename _Tp>
+ auto
+ __invoke_memobj_deref_try(int, _MemFun&& __f, _Tp&& __t)
+ -> decltype( std::forward<_Tp>(__t)->*std::forward<_MemFun>(__f) )
+ {
+ return std::forward<_Tp>(__t)->*std::forward<_MemFun>(__f);
+ }
+
+ // Fallback overload if the above is ill-formed
+ template<typename _MemFun, typename _Tp>
+ auto
+ __invoke_memobj_deref_try(long, _MemFun&& __f, _Tp&& __t)
+ -> decltype( (*std::forward<_Tp>(__t)).*std::forward<_MemFun>(__f) )
+ {
+ return (*std::forward<_Tp>(__t)).*std::forward<_MemFun>(__f);
+ }
+
+ template<typename _Res, typename _MemFun, typename _Tp, typename... _Args>
+ constexpr _Res
+ __invoke_impl(__invoke_memobj_deref, _MemFun&& __f, _Tp&& __t,
_Args&&... __args)
+ {
+ // int preferred, long fallback
+ return __invoke_memobj_deref_try(0,
+ std::forward<_MemFun>(__f),
+ std::forward<_Tp>(__t),
+ std::forward<_Args>(__args)...);
+ }
/// Invoke a callable object.
template<typename _Callable, typename... _Args>
diff --git a/libstdc++-v3/include/std/type_traits
b/libstdc++-v3/include/std/type_traits
index cb00074effc..a07dd79bfe6 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -2756,9 +2756,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __result_of_memfun_deref_impl
{
template<typename _Fp, typename _Tp1, typename... _Args>
- static __result_of_success<decltype(
- ((*std::declval<_Tp1>()).*std::declval<_Fp>())(std::declval<_Args>()...)
- ), __invoke_memfun_deref> _S_test(int);
+ static auto _S_test(int) -> __result_of_success<
+ decltype(
(std::declval<_Tp1>()->*std::declval<_Fp>())(std::declval<_Args>()...)
),
+ __invoke_memfun_deref>;
+
+ template<typename _Fp, typename _Tp1, typename... _Args>
+ static auto _S_test(long) -> __result_of_success<
+ decltype(
((*std::declval<_Tp1>()).*std::declval<_Fp>())(std::declval<_Args>()...)
),
+ __invoke_memfun_deref>;
template<typename...>
static __failure_type _S_test(...);
@@ -2794,9 +2799,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __result_of_memobj_deref_impl
{
template<typename _Fp, typename _Tp1>
- static __result_of_success<decltype(
- (*std::declval<_Tp1>()).*std::declval<_Fp>()
- ), __invoke_memobj_deref> _S_test(int);
+ static auto _S_test(int) -> __result_of_success<
+ decltype( std::declval<_Tp1>()->*std::declval<_Fp>() ),
+ __invoke_memobj_deref>;
+
+ template<typename _Fp, typename _Tp1>
+ static auto _S_test(long) -> __result_of_success<
+ decltype( (*std::declval<_Tp1>()).*std::declval<_Fp>() ),
+ __invoke_memobj_deref>;
template<typename, typename>
static __failure_type _S_test(...);
More information about the Libstdc++
mailing list