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

Closes: #1992
PiperOrigin-RevId: 857136106
Change-Id: Iae31d7c6c9a0fda16ebf2c4f68764da521d036bf
This commit is contained in:
Abseil Team
2026-01-16 06:33:14 -08:00
committed by Copybara-Service
parent eef1a08f4b
commit 28e6a799ba
2 changed files with 46 additions and 2 deletions

View File

@@ -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 @@ ABSL_NAMESPACE_BEGIN
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 @@ 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 <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 @@ class Condition {
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) {

View File

@@ -993,6 +993,20 @@ TEST(Mutex, FunctionPointerConditionWithConstMethod) {
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 {