diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index b999d6ef8..5a04d7fac 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -376,11 +376,16 @@ class MatcherCastImpl { // M can't be implicitly converted to Matcher, so M isn't a polymorphic // matcher. It's a value of a type implicitly convertible to T. Use direct - // initialization to create a matcher. + // initialization or `ImplicitCastEqMatcher` to create a matcher. static Matcher CastImpl(const M& value, std::false_type /* convertible_to_matcher */, std::true_type /* convertible_to_T */) { - return Matcher(ImplicitCast_(value)); + using NoRefT = std::remove_cv_t>; + if constexpr (std::is_same_v) { + return Matcher(value); + } else { + return ImplicitCastEqMatcher>(value); + } } // M can't be implicitly converted to either Matcher or T. Attempt to use @@ -391,11 +396,11 @@ class MatcherCastImpl { // latter calls bool operator==(const Lhs& lhs, const Rhs& rhs) in the end // which might be undefined even when Rhs is implicitly convertible to Lhs // (e.g. std::pair vs. std::pair). - // - // We don't define this method inline as we need the declaration of Eq(). static Matcher CastImpl(const M& value, std::false_type /* convertible_to_matcher */, - std::false_type /* convertible_to_T */); + std::false_type /* convertible_to_T */) { + return Eq(value); + } }; // This more specialized version is used when MatcherCast()'s argument @@ -4483,13 +4488,6 @@ inline Matcher An() { return _; } -template -Matcher internal::MatcherCastImpl::CastImpl( - const M& value, std::false_type /* convertible_to_matcher */, - std::false_type /* convertible_to_T */) { - return Eq(value); -} - // Creates a polymorphic matcher that matches any NULL pointer. inline PolymorphicMatcher IsNull() { return MakePolymorphicMatcher(internal::IsNullMatcher()); diff --git a/googlemock/test/gmock-matchers-comparisons_test.cc b/googlemock/test/gmock-matchers-comparisons_test.cc index 87eca08f5..413c2bb0e 100644 --- a/googlemock/test/gmock-matchers-comparisons_test.cc +++ b/googlemock/test/gmock-matchers-comparisons_test.cc @@ -622,15 +622,42 @@ struct IntReferenceWrapper { const int* value; }; +// Compared the contained values bool operator==(const IntReferenceWrapper& a, const IntReferenceWrapper& b) { - return a.value == b.value; + return *a.value == *b.value; } -TEST(MatcherCastTest, ValueIsNotCopied) { - int n = 42; - Matcher m = MatcherCast(n); - // Verify that the matcher holds a reference to n, not to its temporary copy. - EXPECT_TRUE(m.Matches(n)); +TEST(MatcherCastTest, ValueIsCopied) { + { + // When an IntReferenceWrapper is passed. + int n = 42; + Matcher m = + MatcherCast(IntReferenceWrapper(n)); + { + int value = 42; + EXPECT_TRUE(m.Matches(value)); + value = 10; + EXPECT_FALSE(m.Matches(value)); + // This changes the stored reference. + n = 10; + EXPECT_TRUE(m.Matches(value)); + } + } + + { + // When an int is passed. + int n = 42; + Matcher m = MatcherCast(n); + { + int value = 42; + EXPECT_TRUE(m.Matches(value)); + value = 10; + EXPECT_FALSE(m.Matches(value)); + // This does not change the stored int. + n = 10; + EXPECT_FALSE(m.Matches(value)); + } + } } class Base { diff --git a/googletest/include/gtest/gtest-matchers.h b/googletest/include/gtest/gtest-matchers.h index 78160f0e4..93643dba1 100644 --- a/googletest/include/gtest/gtest-matchers.h +++ b/googletest/include/gtest/gtest-matchers.h @@ -773,6 +773,35 @@ class GeMatcher static const char* NegatedDesc() { return "isn't >="; } }; +// Same as `EqMatcher`, except that the `rhs` is stored as `StoredRhs` and +// must be implicitly convertible to `Rhs`. +template +class ImplicitCastEqMatcher { + public: + explicit ImplicitCastEqMatcher(const StoredRhs& rhs) : stored_rhs_(rhs) {} + + using is_gtest_matcher = void; + + template + bool MatchAndExplain(const Lhs& lhs, std::ostream*) const { + return lhs == rhs(); + } + + void DescribeTo(std::ostream* os) const { + *os << "is equal to "; + UniversalPrint(rhs(), os); + } + void DescribeNegationTo(std::ostream* os) const { + *os << "isn't equal to "; + UniversalPrint(rhs(), os); + } + + private: + Rhs rhs() const { return ImplicitCast_(stored_rhs_); } + + StoredRhs stored_rhs_; +}; + template ::value>::type> using StringLike = T;