__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