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
This commit is contained in:
Abseil Team 2026-03-05 10:07:49 -08:00 committed by Copybara-Service
parent 73a63ea05d
commit a35bc7693c
2 changed files with 31 additions and 12 deletions

View File

@ -2602,9 +2602,9 @@ class [[nodiscard]] WhenSortedByMatcher {
typedef typename LhsView::const_reference LhsStlContainerReference;
// Transforms std::pair<const Key, Value> into std::pair<Key, Value>
// so that we can match associative containers.
typedef
typename RemoveConstFromKey<typename LhsStlContainer::value_type>::type
LhsValue;
typedef typename RemoveConstFromKey<
typename internal::RangeTraits<LhsStlContainer>::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<RhsContainer> RhsView;
typedef typename RhsView::type RhsStlContainer;
typedef typename RhsStlContainer::value_type RhsValue;
typedef typename internal::RangeTraits<RhsStlContainer>::value_type RhsValue;
static_assert(!std::is_const<RhsContainer>::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<LhsStlContainer>::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<Container> {
typedef StlContainerView<RawContainer> View;
typedef typename View::type StlContainer;
typedef typename View::const_reference StlContainerReference;
typedef typename StlContainer::value_type Element;
typedef typename internal::RangeTraits<StlContainer>::value_type Element;
template <typename InnerMatcher>
explicit QuantifierMatcherImpl(InnerMatcher inner_matcher)
@ -3600,7 +3601,7 @@ class [[nodiscard]] ElementsAreMatcherImpl
typedef internal::StlContainerView<RawContainer> View;
typedef typename View::type StlContainer;
typedef typename View::const_reference StlContainerReference;
typedef typename StlContainer::value_type Element;
typedef typename internal::RangeTraits<StlContainer>::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<RawContainer> View;
typedef typename View::type StlContainer;
typedef typename View::const_reference StlContainerReference;
typedef typename StlContainer::value_type Element;
typedef typename internal::RangeTraits<StlContainer>::value_type Element;
template <typename InputIter>
UnorderedElementsAreMatcherImpl(UnorderedMatcherRequire::Flags matcher_flags,
@ -3963,8 +3964,7 @@ class [[nodiscard]] UnorderedElementsAreMatcher {
template <typename Container>
operator Matcher<Container>() const {
typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type View;
typedef typename View::value_type Element;
typedef typename internal::RangeTraits<RawContainer>::value_type Element;
typedef ::std::vector<Matcher<const Element&>> MatcherVec;
MatcherVec matchers;
matchers.reserve(::std::tuple_size<MatcherTuple>::value);
@ -3995,7 +3995,7 @@ class [[nodiscard]] ElementsAreMatcher {
typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type View;
typedef typename View::value_type Element;
typedef typename internal::RangeTraits<View>::value_type Element;
typedef ::std::vector<Matcher<const Element&>> MatcherVec;
MatcherVec matchers;
matchers.reserve(::std::tuple_size<MatcherTuple>::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<RhsContainer> RhsView;
typedef typename RhsView::type RhsStlContainer;
typedef typename RhsStlContainer::value_type Second;
typedef typename internal::RangeTraits<RhsStlContainer>::value_type Second;
const RhsStlContainer& rhs_stl_container =
RhsView::ConstReference(rhs_container);

View File

@ -41,6 +41,7 @@
#include <stdio.h>
#include <iterator>
#include <ostream> // NOLINT
#include <string>
#include <type_traits>
@ -322,6 +323,24 @@ inline T Invalid() {
#endif
}
void GetValueType(const void*);
template <class T>
typename std::iterator_traits<
decltype(std::begin(std::declval<T&>()))>::value_type
GetValueType(T*);
template <class T, class = void>
struct RangeTraits {
typedef decltype(internal::GetValueType(
static_cast<std::remove_reference_t<T>*>(nullptr))) value_type;
};
template <class T>
struct RangeTraits<T, std::conditional_t<true, void, typename T::value_type>> {
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<RawContainer> has the