判断三角形退化的Eigen模板不支持固定尺寸矩阵如何修复
错误原因
- 代码中使用运行时
if判断矩阵列数,而C++编译阶段会实例化所有分支的代码。当传入固定列数为2的矩阵时,cols() == 3分支的代码也会被编译,该分支中尝试将2列的行向量赋值给固定尺寸Matrix<scalarType, 1, 3>,触发Eigen的静态尺寸校验报错。 - 动态尺寸矩阵不会触发该问题,是因为动态尺寸的校验在运行时执行,而
cols()==3的分支运行时不会进入,因此不会触发运行时错误。
解决方案
下面给出两种常用的兼容方案:
方案1:C++17及以上版本使用if constexpr做编译期分支剪枝
该方案代码最简洁,编译期会根据输入矩阵的固定尺寸自动剪枝不符合的分支,不会实例化错误分支的代码:
#include <Eigen/Core> #include <iostream> template<typename Derived> bool nondegenerate(const Eigen::PlainObjectBase<Derived>& triangle) { using scalarType = typename Derived::Scalar; constexpr int Cols = Derived::ColsAtCompileTime; if constexpr (Cols == 2 || Cols == Eigen::Dynamic) { if (triangle.cols() == 2) { const auto v1 = triangle.row(1) - triangle.row(0); const auto v2 = triangle.row(2) - triangle.row(0); return static_cast<bool>(v1(0) * v2(1) - v1(1) * v2(0)); } } if constexpr (Cols == 3 || Cols == Eigen::Dynamic) { if (triangle.cols() == 3) { const auto v1 = triangle.row(1) - triangle.row(0); const auto v2 = triangle.row(2) - triangle.row(0); return static_cast<bool>(v1.cross(v2).norm()); } } std::cerr << "Undefined input." << std::endl; return false; }
方案2:C++11及更早版本使用编译期分发实现兼容
如果编译器不支持C++17,可以借助Eigen自带的Int2Type工具把不同维度的处理逻辑拆分为重载函数,实现编译期分支分发:
#include <Eigen/Core> #include <iostream> // 处理2维三角形 template<typename Derived> bool nondegenerate_impl(const Eigen::PlainObjectBase<Derived>& triangle, Eigen::Int2Type<2>) { const auto v1 = triangle.row(1) - triangle.row(0); const auto v2 = triangle.row(2) - triangle.row(0); return static_cast<bool>(v1(0) * v2(1) - v1(1) * v2(0)); } // 处理3维三角形 template<typename Derived> bool nondegenerate_impl(const Eigen::PlainObjectBase<Derived>& triangle, Eigen::Int2Type<3>) { const auto v1 = triangle.row(1) - triangle.row(0); const auto v2 = triangle.row(2) - triangle.row(0); return static_cast<bool>(v1.cross(v2).norm()); } // 处理动态尺寸矩阵的运行时分发 template<typename Derived> bool nondegenerate_impl(const Eigen::PlainObjectBase<Derived>& triangle, Eigen::Int2Type<Eigen::Dynamic>) { if (triangle.cols() == 2) { return nondegenerate_impl(triangle, Eigen::Int2Type<2>()); } else if (triangle.cols() == 3) { return nondegenerate_impl(triangle, Eigen::Int2Type<3>()); } else { std::cerr << "Undefined input." << std::endl; return false; } } // 对外调用入口 template<typename Derived> bool nondegenerate(const Eigen::PlainObjectBase<Derived>& triangle) { return nondegenerate_impl(triangle, Eigen::Int2Type<Derived::ColsAtCompileTime>()); }
两种方案都可以同时兼容固定尺寸、动态尺寸的Eigen矩阵输入。
内容的提问来源于stack exchange,提问作者chaohuang
相关产品推荐
相关产品推荐

