GTest使用ElementsAre测试vector<reference_wrapper<T>>编译报错问题
编译失败根因分析
1. C++标准版本升级的影响
- C11/14标准中,
std::reference_wrapper没有内置的operator==重载,两个reference_wrapper实例做相等比较时,会先触发隐式类型转换为底层的T&类型,再调用T的相等运算符完成比较,因此你的代码在C11环境下可以正常编译。 - C++17标准新增了
std::reference_wrapper的内置operator==重载,逻辑为直接比较两个reference_wrapper存储的底层指针地址。且该版本的运算符重载默认不支持const修饰的reference_wrapper左操作数调用,刚好匹配你遇到的C2678错误描述。
2. GTest版本升级的影响
- GTest 1.8.1版本的
ElementsAre匹配器内部实现会自动做隐式类型转换,遇到reference_wrapper类型时会先解引用为底层值再比较,不会触发reference_wrapper自身的operator==调用。 - GTest 1.11版本优化了匹配器的类型推导逻辑,减少了非必要的隐式转换以提升类型安全性,会直接尝试对容器中取出的
const std::reference_wrapper<T>实例调用operator==,刚好触发了C++17下的运算符不兼容问题。
可行解决方案
你可以根据实际测试需求选择任意一种方案修复:
- 方案1:使用GTest内置的
Ref匹配器,专门适配reference_wrapper类型的比较:
EXPECT_THAT(vec, ElementsAre(Ref(s1), Ref(s2), Ref(s3)));
- 方案2:显式解引用
reference_wrapper后比较底层值:
EXPECT_THAT(vec, ElementsAre( ResultOf([](const auto& rw) { return rw.get(); }, Eq(s1)), ResultOf([](const auto& rw) { return rw.get(); }, Eq(s2)), ResultOf([](const auto& rw) { return rw.get(); }, Eq(s3)) ));
- 方案3:如果测试逻辑需要确认引用指向的是同一个对象,也可以显式转为指针比较地址:
EXPECT_THAT(vec, ElementsAre( ResultOf([](const auto& rw) { return &rw.get(); }, Eq(&s1)), ResultOf([](const auto& rw) { return &rw.get(); }, Eq(&s2)), ResultOf([](const auto& rw) { return &rw.get(); }, Eq(&s3)) ));
内容的提问来源于stack exchange,提问作者Mr. Boy
相关产品推荐
相关产品推荐

