From 28e6a799ba550f8d499bfda5e100d16937804f72 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 16 Jan 2026 06:33:14 -0800 Subject: [PATCH] Make absl::Condition work with C++23 deducing-this Closes: #1992 PiperOrigin-RevId: 857136106 Change-Id: Iae31d7c6c9a0fda16ebf2c4f68764da521d036bf --- absl/synchronization/mutex.h | 34 ++++++++++++++++++++++++++++-- absl/synchronization/mutex_test.cc | 14 ++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h index 39ea0d0f23e..ad156d443d6 100644 --- a/absl/synchronization/mutex.h +++ b/absl/synchronization/mutex.h @@ -61,6 +61,7 @@ #include #include #include +#include #include "absl/base/attributes.h" #include "absl/base/config.h" @@ -81,6 +82,18 @@ ABSL_NAMESPACE_BEGIN class Condition; struct SynchWaitParams; +namespace synchronization_internal { + +template +struct HasConstMemberCallOperator : std::false_type {}; + +template +struct HasConstMemberCallOperator< + T, std::void_t(&T::operator()))>> + : std::true_type {}; + +} // namespace synchronization_internal + // ----------------------------------------------------------------------------- // Mutex // ----------------------------------------------------------------------------- @@ -866,11 +879,23 @@ class Condition { // 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 ( - &T::operator()))> + template ::value, + int> = 0> explicit Condition(const T* absl_nonnull obj) : Condition(obj, static_cast(&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::value && + sizeof(static_cast(&T::operator())) != 0>> + explicit Condition(const T* absl_nonnull obj) + : Condition(&CallByRef, 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 @@ class Condition { template static bool CastAndCallMethod(const Condition* absl_nonnull c); + template + static bool CallByRef(const T* absl_nonnull self) { + return (*self)(); + } + // Helper methods for storing, validating, and reading callback arguments. template inline void StoreCallback(T callback) { diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc index 793acf8c01d..38c869124f3 100644 --- a/absl/synchronization/mutex_test.cc +++ b/absl/synchronization/mutex_test.cc @@ -993,6 +993,20 @@ TEST(Mutex, FunctionPointerConditionWithConstMethod) { EXPECT_TRUE(absl::Condition(&chapman, &Constable::WotsAllThisThen).Eval()); } +#ifdef __cpp_explicit_this_parameter +struct TrueViaDeducingThis { + template + bool operator()(this const This&, Args...) { + return true; + } +}; + +TEST(Mutex, FunctorConditionDeducingThis) { + TrueViaDeducingThis f; + EXPECT_TRUE(absl::Condition(&f).Eval()); +} +#endif + struct True { template bool operator()(Args...) const {