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:09:30 -08:00
committed by Copybara-Service
parent 73a63ea05d
commit a35bc7693c
2 changed files with 31 additions and 12 deletions
+12 -12
View File
@@ -2602,9 +2602,9 @@ class [[nodiscard]] WhenSortedByMatcher {
typedef typename LhsView::const_reference LhsStlContainerReference; typedef typename LhsView::const_reference LhsStlContainerReference;
// Transforms std::pair<const Key, Value> into std::pair<Key, Value> // Transforms std::pair<const Key, Value> into std::pair<Key, Value>
// so that we can match associative containers. // so that we can match associative containers.
typedef typedef typename RemoveConstFromKey<
typename RemoveConstFromKey<typename LhsStlContainer::value_type>::type typename internal::RangeTraits<LhsStlContainer>::value_type>::type
LhsValue; LhsValue;
Impl(const Comparator& comparator, const ContainerMatcher& matcher) Impl(const Comparator& comparator, const ContainerMatcher& matcher)
: comparator_(comparator), matcher_(matcher) {} : comparator_(comparator), matcher_(matcher) {}
@@ -2670,7 +2670,7 @@ class [[nodiscard]] PointwiseMatcher {
public: public:
typedef internal::StlContainerView<RhsContainer> RhsView; typedef internal::StlContainerView<RhsContainer> RhsView;
typedef typename RhsView::type RhsStlContainer; 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, static_assert(!std::is_const<RhsContainer>::value,
"RhsContainer type must not be const"); "RhsContainer type must not be const");
@@ -2700,7 +2700,8 @@ class [[nodiscard]] PointwiseMatcher {
LhsView; LhsView;
typedef typename LhsView::type LhsStlContainer; typedef typename LhsView::type LhsStlContainer;
typedef typename LhsView::const_reference LhsStlContainerReference; 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 // 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 // reference, as they may be expensive to copy. We must use tuple
// instead of pair here, as a pair cannot hold references (C++ 98, // 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 StlContainerView<RawContainer> View;
typedef typename View::type StlContainer; typedef typename View::type StlContainer;
typedef typename View::const_reference StlContainerReference; typedef typename View::const_reference StlContainerReference;
typedef typename StlContainer::value_type Element; typedef typename internal::RangeTraits<StlContainer>::value_type Element;
template <typename InnerMatcher> template <typename InnerMatcher>
explicit QuantifierMatcherImpl(InnerMatcher inner_matcher) explicit QuantifierMatcherImpl(InnerMatcher inner_matcher)
@@ -3600,7 +3601,7 @@ class [[nodiscard]] ElementsAreMatcherImpl
typedef internal::StlContainerView<RawContainer> View; typedef internal::StlContainerView<RawContainer> View;
typedef typename View::type StlContainer; typedef typename View::type StlContainer;
typedef typename View::const_reference StlContainerReference; 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 // Constructs the matcher from a sequence of element values or
// element matchers. // element matchers.
@@ -3875,7 +3876,7 @@ class [[nodiscard]] UnorderedElementsAreMatcherImpl
typedef internal::StlContainerView<RawContainer> View; typedef internal::StlContainerView<RawContainer> View;
typedef typename View::type StlContainer; typedef typename View::type StlContainer;
typedef typename View::const_reference StlContainerReference; typedef typename View::const_reference StlContainerReference;
typedef typename StlContainer::value_type Element; typedef typename internal::RangeTraits<StlContainer>::value_type Element;
template <typename InputIter> template <typename InputIter>
UnorderedElementsAreMatcherImpl(UnorderedMatcherRequire::Flags matcher_flags, UnorderedElementsAreMatcherImpl(UnorderedMatcherRequire::Flags matcher_flags,
@@ -3963,8 +3964,7 @@ class [[nodiscard]] UnorderedElementsAreMatcher {
template <typename Container> template <typename Container>
operator Matcher<Container>() const { operator Matcher<Container>() const {
typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type View; typedef typename internal::RangeTraits<RawContainer>::value_type Element;
typedef typename View::value_type Element;
typedef ::std::vector<Matcher<const Element&>> MatcherVec; typedef ::std::vector<Matcher<const Element&>> MatcherVec;
MatcherVec matchers; MatcherVec matchers;
matchers.reserve(::std::tuple_size<MatcherTuple>::value); matchers.reserve(::std::tuple_size<MatcherTuple>::value);
@@ -3995,7 +3995,7 @@ class [[nodiscard]] ElementsAreMatcher {
typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer; typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
typedef typename internal::StlContainerView<RawContainer>::type View; 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; typedef ::std::vector<Matcher<const Element&>> MatcherVec;
MatcherVec matchers; MatcherVec matchers;
matchers.reserve(::std::tuple_size<MatcherTuple>::value); 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. // STL-style container and it being a native C-style array.
typedef typename internal::StlContainerView<RhsContainer> RhsView; typedef typename internal::StlContainerView<RhsContainer> RhsView;
typedef typename RhsView::type RhsStlContainer; typedef typename RhsView::type RhsStlContainer;
typedef typename RhsStlContainer::value_type Second; typedef typename internal::RangeTraits<RhsStlContainer>::value_type Second;
const RhsStlContainer& rhs_stl_container = const RhsStlContainer& rhs_stl_container =
RhsView::ConstReference(rhs_container); RhsView::ConstReference(rhs_container);
@@ -41,6 +41,7 @@
#include <stdio.h> #include <stdio.h>
#include <iterator>
#include <ostream> // NOLINT #include <ostream> // NOLINT
#include <string> #include <string>
#include <type_traits> #include <type_traits>
@@ -322,6 +323,24 @@ inline T Invalid() {
#endif #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 // Given a raw type (i.e. having no top-level reference or const
// modifier) RawContainer that's either an STL-style container or a // modifier) RawContainer that's either an STL-style container or a
// native array, class StlContainerView<RawContainer> has the // native array, class StlContainerView<RawContainer> has the