如何带容差比较QVector3D或Eigen::Vector3d相等并适配Boost.Test
Boost.Test 提供了专门的自定义扩展点来实现逐元素容差比较需求,不需要给向量类型实现大于、小于这类全序比较运算符,也不用依赖默认的tolerance_based单值比较逻辑,所有实现都可以只写在测试代码中,不侵入生产代码。
方案1:特化比较实现扩展点(最推荐,原生支持容差传参)
这是Boost.Test预留的相等/不等判断扩展入口,特化后可以完全复用BOOST_TEST原生的容差语法,支持全局容差配置、单条用例自定义容差,和内置浮点类型的比较体验完全一致。
假设你的向量类型定义如下(不需要修改这段生产代码):
struct MathVec3 { double x, y, z; };
只需要在测试代码中添加如下模板特化即可:
#include <boost/test/unit_test.hpp> #include <boost/test/tools/floating_point_comparison.hpp> namespace boost::test_tools::tt_detail { // 相等判断特化 template<> struct compare_impl<MathVec3, MathVec3, equal_op> { static bool run( const MathVec3& lhs, const MathVec3& rhs, const fpc::tolerance<double>& tol ) { // 逐元素调用Boost原生的浮点容差比较 return fpc::close_at_tolerance<double>(tol)(lhs.x, rhs.x) && fpc::close_at_tolerance<double>(tol)(lhs.y, rhs.y) && fpc::close_at_tolerance<double>(tol)(lhs.z, rhs.z); } }; // 不等判断直接复用相等逻辑取反 template<> struct compare_impl<MathVec3, MathVec3, ne_op> { static bool run( const MathVec3& lhs, const MathVec3& rhs, const fpc::tolerance<double>& tol ) { return !compare_impl<MathVec3, MathVec3, equal_op>::run(lhs, rhs, tol); } }; }
使用方式和普通类型比较完全一致:
BOOST_AUTO_TEST_CASE(vec_compare_test) { MathVec3 a{1.0, 2.0, 3.0}; MathVec3 b{1.0 + 1e-10, 2.0, 3.0}; // 单条用例指定容差 BOOST_TEST(a == b, boost::test_tools::tolerance(1e-9)); // 不等判断自动生效 BOOST_TEST(a != MathVec3{0, 0, 0}); }
如果你的向量是泛型模板(比如Vec<T, N>),只需要把特化改成对应模板形式,逐元素遍历维度即可,逻辑和非模板版本完全一致。
方案2:自定义比较谓词(零模板特化,适合快速实现)
如果你不想接触Boost的内部模板细节,可以直接写自定义比较谓词,传入BOOST_TEST即可,写法更直白:
// 测试代码中定义比较逻辑 bool vec_close(const MathVec3& lhs, const MathVec3& rhs, double eps = 1e-9) { return std::abs(lhs.x - rhs.x) < eps && std::abs(lhs.y - rhs.y) < eps && std::abs(lhs.z - rhs.z) < eps; } BOOST_AUTO_TEST_CASE(vec_compare_simple) { MathVec3 a{1.0, 2.0, 3.0}; MathVec3 b{1.0 + 1e-10, 2.0, 3.0}; BOOST_TEST(vec_close(a, b)); BOOST_TEST(!vec_close(a, MathVec3{0,0,0})); }
这个方案的缺点是不能直接复用==/!=运算符语法,也不能自动读取全局配置的容差参数,适合简单测试场景快速使用。
避坑提示
不要通过特化boost::math::fpc::tolerance_based后依赖默认比较逻辑实现需求:默认逻辑会把整个类型实例当成单个浮点值计算差值,不会自动逐元素遍历,比较结果完全不符合预期。
内容的提问来源于stack exchange,提问作者rubenvb
相关产品推荐
相关产品推荐

