Make absl::Condition work with C++23 deducing-this

Closes: #1992
PiperOrigin-RevId: 857136106
Change-Id: Iae31d7c6c9a0fda16ebf2c4f68764da521d036bf
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h
index 39ea0d0..ad156d4 100644
--- a/absl/synchronization/mutex.h
+++ b/absl/synchronization/mutex.h
@@ -61,6 +61,7 @@
 #include <atomic>
 #include <cstdint>
 #include <cstring>
+#include <type_traits>
 
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
@@ -81,6 +82,18 @@
 class Condition;
 struct SynchWaitParams;
 
+namespace synchronization_internal {
+
+template <typename T, typename = void>
+struct HasConstMemberCallOperator : std::false_type {};
+
+template <typename T>
+struct HasConstMemberCallOperator<
+    T, std::void_t<decltype(static_cast<bool (T::*)() const>(&T::operator()))>>
+    : std::true_type {};
+
+}  // namespace synchronization_internal
+
 // -----------------------------------------------------------------------------
 // Mutex
 // -----------------------------------------------------------------------------
@@ -866,11 +879,23 @@
   // Implementation note: The second template parameter ensures that this
   // constructor doesn't participate in overload resolution if T doesn't have
   // `bool operator() const`.
-  template <typename T, typename E = decltype(static_cast<bool (T::*)() const>(
-                            &T::operator()))>
+  template <typename T,
+            std::enable_if_t<
+                synchronization_internal::HasConstMemberCallOperator<T>::value,
+                int> = 0>
   explicit Condition(const T* absl_nonnull obj)
       : Condition(obj, static_cast<bool (T::*)() const>(&T::operator())) {}
 
+  // Constructor for functors that do not match the `bool operator()() const`
+  // signature, such as those using C++23 "deducing this" or static operator().
+  template <
+      typename T,
+      typename = std::enable_if_t<
+          !synchronization_internal::HasConstMemberCallOperator<T>::value &&
+          sizeof(static_cast<bool (*)(const T&)>(&T::operator())) != 0>>
+  explicit Condition(const T* absl_nonnull obj)
+      : Condition(&CallByRef<T>, obj) {}
+
   // A Condition that always returns `true`.
   // kTrue is only useful in a narrow set of circumstances, mostly when
   // it's passed conditionally. For example:
@@ -932,6 +957,11 @@
   template <typename T, typename ConditionMethodPtr>
   static bool CastAndCallMethod(const Condition* absl_nonnull c);
 
+  template <typename T>
+  static bool CallByRef(const T* absl_nonnull self) {
+    return (*self)();
+  }
+
   // Helper methods for storing, validating, and reading callback arguments.
   template <typename T>
   inline void StoreCallback(T callback) {
diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc
index 793acf8..38c8691 100644
--- a/absl/synchronization/mutex_test.cc
+++ b/absl/synchronization/mutex_test.cc
@@ -993,6 +993,20 @@
   EXPECT_TRUE(absl::Condition(&chapman, &Constable::WotsAllThisThen).Eval());
 }
 
+#ifdef __cpp_explicit_this_parameter
+struct TrueViaDeducingThis {
+  template <class This, class... Args>
+  bool operator()(this const This&, Args...) {
+    return true;
+  }
+};
+
+TEST(Mutex, FunctorConditionDeducingThis) {
+  TrueViaDeducingThis f;
+  EXPECT_TRUE(absl::Condition(&f).Eval());
+}
+#endif
+
 struct True {
   template <class... Args>
   bool operator()(Args...) const {