From a35bc7693c117a048152beeb34f6aac354b9423f Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Thu, 5 Mar 2026 10:07:49 -0800 Subject: [PATCH] Make gmock-matchers.h auto-detect the value_type of ranges that don't have a typedef for it based on the ranges' iterators This is needed for ranges such as [`std::ranges::subrange`](https://en.cppreference.com/w/cpp/ranges/subrange.html) that don't expose the typical typedefs. PiperOrigin-RevId: 879124865 Change-Id: Ie89e6ff249ee861d1b2d880079dc162bb9801679 --- googlemock/include/gmock/gmock-matchers.h | 24 +++++++++---------- .../gmock/internal/gmock-internal-utils.h | 19 +++++++++++++++ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index 2532d597..2f49371a 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -2602,9 +2602,9 @@ class [[nodiscard]] WhenSortedByMatcher { typedef typename LhsView::const_reference LhsStlContainerReference; // Transforms std::pair into std::pair // so that we can match associative containers. - typedef - typename RemoveConstFromKey::type - LhsValue; + typedef typename RemoveConstFromKey< + typename internal::RangeTraits::value_type>::type + LhsValue; Impl(const Comparator& comparator, const ContainerMatcher& matcher) : comparator_(comparator), matcher_(matcher) {} @@ -2670,7 +2670,7 @@ class [[nodiscard]] PointwiseMatcher { public: typedef internal::StlContainerView RhsView; typedef typename RhsView::type RhsStlContainer; - typedef typename RhsStlContainer::value_type RhsValue; + typedef typename internal::RangeTraits::value_type RhsValue; static_assert(!std::is_const::value, "RhsContainer type must not be const"); @@ -2700,7 +2700,8 @@ class [[nodiscard]] PointwiseMatcher { LhsView; typedef typename LhsView::type LhsStlContainer; typedef typename LhsView::const_reference LhsStlContainerReference; - typedef typename LhsStlContainer::value_type LhsValue; + typedef + typename internal::RangeTraits::value_type LhsValue; // We pass the LHS value and the RHS value to the inner matcher by // reference, as they may be expensive to copy. We must use tuple // instead of pair here, as a pair cannot hold references (C++ 98, @@ -2786,7 +2787,7 @@ class [[nodiscard]] QuantifierMatcherImpl : public MatcherInterface { typedef StlContainerView View; typedef typename View::type StlContainer; typedef typename View::const_reference StlContainerReference; - typedef typename StlContainer::value_type Element; + typedef typename internal::RangeTraits::value_type Element; template explicit QuantifierMatcherImpl(InnerMatcher inner_matcher) @@ -3600,7 +3601,7 @@ class [[nodiscard]] ElementsAreMatcherImpl typedef internal::StlContainerView View; typedef typename View::type StlContainer; typedef typename View::const_reference StlContainerReference; - typedef typename StlContainer::value_type Element; + typedef typename internal::RangeTraits::value_type Element; // Constructs the matcher from a sequence of element values or // element matchers. @@ -3875,7 +3876,7 @@ class [[nodiscard]] UnorderedElementsAreMatcherImpl typedef internal::StlContainerView View; typedef typename View::type StlContainer; typedef typename View::const_reference StlContainerReference; - typedef typename StlContainer::value_type Element; + typedef typename internal::RangeTraits::value_type Element; template UnorderedElementsAreMatcherImpl(UnorderedMatcherRequire::Flags matcher_flags, @@ -3963,8 +3964,7 @@ class [[nodiscard]] UnorderedElementsAreMatcher { template operator Matcher() const { typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; - typedef typename internal::StlContainerView::type View; - typedef typename View::value_type Element; + typedef typename internal::RangeTraits::value_type Element; typedef ::std::vector> MatcherVec; MatcherVec matchers; matchers.reserve(::std::tuple_size::value); @@ -3995,7 +3995,7 @@ class [[nodiscard]] ElementsAreMatcher { typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef typename internal::StlContainerView::type View; - typedef typename View::value_type Element; + typedef typename internal::RangeTraits::value_type Element; typedef ::std::vector> MatcherVec; MatcherVec matchers; matchers.reserve(::std::tuple_size::value); @@ -5081,7 +5081,7 @@ UnorderedPointwise(const Tuple2Matcher& tuple2_matcher, // STL-style container and it being a native C-style array. typedef typename internal::StlContainerView RhsView; typedef typename RhsView::type RhsStlContainer; - typedef typename RhsStlContainer::value_type Second; + typedef typename internal::RangeTraits::value_type Second; const RhsStlContainer& rhs_stl_container = RhsView::ConstReference(rhs_container); diff --git a/googlemock/include/gmock/internal/gmock-internal-utils.h b/googlemock/include/gmock/internal/gmock-internal-utils.h index 2e746f82..258397a4 100644 --- a/googlemock/include/gmock/internal/gmock-internal-utils.h +++ b/googlemock/include/gmock/internal/gmock-internal-utils.h @@ -41,6 +41,7 @@ #include +#include #include // NOLINT #include #include @@ -322,6 +323,24 @@ inline T Invalid() { #endif } +void GetValueType(const void*); + +template +typename std::iterator_traits< + decltype(std::begin(std::declval()))>::value_type +GetValueType(T*); + +template +struct RangeTraits { + typedef decltype(internal::GetValueType( + static_cast*>(nullptr))) value_type; +}; + +template +struct RangeTraits> { + typedef typename T::value_type value_type; +}; + // Given a raw type (i.e. having no top-level reference or const // modifier) RawContainer that's either an STL-style container or a // native array, class StlContainerView has the