C++函数模板无法推导Eigen向量维度N的问题求助
我编写了如下函数模板:
template <int N> bool checkColinear(const std::array<Eigen::Vector<double, N>, 3>& points) noexcept;
该函数接收3个N维点,若它们在特定容差内共线则返回true。显式指定N调用时一切正常:
std::array<Eigen::Vector3d, 3> points = {Eigen::Vector3d{0.0, 1.0, 0.0}, Eigen::Vector3d{0.0, 3.0, 0.0}, Eigen::Vector3d{0.0, 2.0, 0.0}}; auto result = checkCollinear<3>(points);
但省略N直接调用时,编译器报错:error C2672: 'checkCollinear': no matching overloaded function found。我使用MSVC143(VS2022)和C++20标准,已尝试将Eigen::Vector3d改为Eigen::Vector<double, 3>、Eigen::Matrix<double, 3, 1>,也将N的类型改为std::size_t,但均无效。请问这种情况下编译器能否推导模板参数N?
结论:编译器无法自动推导该模板参数N
原因在于:当传递std::array<Eigen::Vector3d, 3>类型的参数时,编译器需要将其与函数参数的std::array<Eigen::Vector<double, N>, 3>匹配,但Eigen::Vector3d是Eigen::Vector<double, 3>的typedef别名。模板参数推导过程中,编译器不会自动展开别名去匹配模板参数N——它只会直接比较类型是否完全一致,Eigen::Vector3d和Eigen::Vector<double, N>在推导阶段被视为不同类型,无法关联到N=3。
解决方法
有两种实用的修复方式:
基于Eigen类型的编译时属性推导:
放弃直接将N作为顶层模板参数,转而从传入的向量类型中提取维度。利用Eigen类型自带的RowsAtCompileTime编译时常量:template <typename Vec> requires (Vec::IsVectorAtCompileTime) bool checkColinear(const std::array<Vec, 3>& points) noexcept { constexpr int N = Vec::RowsAtCompileTime; // 原函数逻辑,使用N即可 // ... return true; }调用时无需指定任何模板参数:
checkColinear(points),编译器会自动推导Vec并获取N。添加模板推导指引(C++17+):
若坚持保留N作为顶层模板参数,可以为函数添加推导指引,帮助编译器关联类型与模板参数:template <int N> bool checkColinear(const std::array<Eigen::Vector<double, N>, 3>& points) noexcept; // 针对Eigen::Vector<double, N>的推导指引 template <int N> checkColinear(const std::array<Eigen::Vector<double, N>, 3>&) -> checkColinear<N>; // 针对Eigen::Vector3d这类别名的推导指引 checkColinear(const std::array<Eigen::Vector3d, 3>&) -> checkColinear<3>;但这种方式需要为每个可能的Eigen向量别名添加对应指引,扩展性较差,仅适合固定维度的场景。
内容的提问来源于stack exchange,提问作者red-patriot

