为层级Element实现Google Test匹配器时编译报错求助
我想要为如下简化后的Element结构体实现Google Test匹配器,用于验证其包含特定元素,后续还希望支持层级匹配,但目前就连简单版本都无法编译:
struct Element { enum class Type { String, Vector }; using Vec = std::vector<Element>; Type GetType() const { return Type::Vector; } std::string GetString() const { return "..."; } Vec GetVec() const { return {}; } };
我尝试了以下代码:
template <typename ValueMatcher> class ElementArrayMatcher { public: explicit ElementArrayMatcher(ValueMatcher value_matcher) : value_matcher_(value_matcher) { } operator testing::Matcher<Element>() const { return testing::Matcher<Element>(new Impl(value_matcher_)); } class Impl : public testing::MatcherInterface<const Element&> { public: using ElementVec = Element::Vec; explicit Impl(const ValueMatcher& value_matcher) : value_matcher_(MatcherCast<ElementVec>(value_matcher)) { } bool MatchAndExplain(const Element& x, testing::MatchResultListener* listener) const override { if (x.GetType() != Element::Type::Vector) { *listener << " Element is not an array, it is of type " << x.GetType(); return false; } return value_matcher_.MatchAndExplain(x.GetVec(), listener); } void DescribeTo(::std::ostream* os) const override { value_matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { value_matcher_.DescribeNegationTo(os); } private: const testing::Matcher<ElementVec> value_matcher_; }; private: const ValueMatcher value_matcher_; }; template <typename InnerMatcher> ElementArrayMatcher<InnerMatcher> ElementArray(const InnerMatcher& inner_matcher) { return ElementArrayMatcher<InnerMatcher>(inner_matcher); } TEST(Test, Test) { Element e; EXPECT_THAT(e, ElementArray(testing::ElementsAre())); }
但编译失败,错误提示试图将Element与ElementArrayMatcher进行==比较:
build-dbg/_deps/gtest-src/googletest/include/gtest/gtest-matchers.h:179:60: error: no match for _operator==_ (operand types are _const Element_ and _const ElementArrayMatcher<testing::internal::ElementsAreMatcher<std::tuple<> > >_) 179 | bool operator()(const A& a, const B& b) const { return a == b; }
我模仿了testing::Optional等匹配器的实现,但仍未找到问题所在,请问我哪里出错了?
问题出在Google Test的模板推导逻辑:当你在EXPECT_THAT中使用ElementArray(...)时,编译器没有触发ElementArrayMatcher到testing::Matcher<Element>的隐式转换,反而将ElementArrayMatcher当作普通值,尝试用默认相等比较逻辑匹配Element对象,导致找不到operator==的编译错误。
有两种可行的解决方式:
显式转换为Matcher类型
在调用时手动将ElementArray的结果转换为testing::Matcher<Element>,让编译器明确识别这是一个匹配器:EXPECT_THAT(e, static_cast<testing::Matcher<Element>>(ElementArray(testing::ElementsAre())));修改工厂函数返回类型(推荐)
直接让ElementArray工厂函数返回testing::Matcher<Element>,而非ElementArrayMatcher,这样编译器会直接识别匹配器类型,无需依赖隐式转换:template <typename InnerMatcher> testing::Matcher<Element> ElementArray(const InnerMatcher& inner_matcher) { return ElementArrayMatcher<InnerMatcher>(inner_matcher); }
第二种方式更贴合Google Test匹配器的使用习惯。另外还可以优化匹配器实现,比如确保Impl构造函数中的MatcherCast正确处理内部匹配器的类型转换,规避潜在类型问题。
内容的提问来源于stack exchange,提问作者chakaz

