如何结合STL Vector使用Eigen::Ref?映射向量传参报错解决
问题描述
需要存储多个不同大小的Eigen映射向量到STL vector中,编写的函数接收const std::vector<Eigen::Ref<Eigen::VectorXd>>&类型参数时触发编译错误。单独使用Eigen::Ref<Eigen::VectorXd>时正常,但结合STL容器后无法完成类型转换。
最小复现代码:
#include <iostream> #include <vector> #include <Eigen/Core> void EigenRefFunction(const std::vector<Eigen::Ref<Eigen::VectorXd>>& vec) { for(int i=0;i<vec.size();++i) { for(int j=0;j<vec[i].rows();++j) { std::cout << i << "," << "j: " << vec[i](j) << std::endl; } } } int main() { // 示例映射源向量 std::vector<double> vec1(10, 1.0); // 存储Eigen::Map的容器 std::vector<Eigen::Map<Eigen::VectorXd>> vec_map; vec_map.push_back(Eigen::Map<Eigen::VectorXd>(vec1.data(), vec1.size())); // 调用函数触发错误 EigenRefFunction(vec_map); }
编译错误信息(Visual Studio v142):
: In function 'int main()': :26:22: error: invalid
initialization of reference of type 'const
std::vector<Eigen::RefEigen::VectorXd, std::allocator<Eigen::RefEigen::VectorXd> >&' from
expression of type 'std::vector<Eigen::Map<Eigen::VectorXd, 0, Eigen::Stride<0, 0> >, std::allocator<Eigen::Map<Eigen::VectorXd, 0, Eigen::Stride<0, 0> > > >' 26 | EigenRefFunction(vec_map);
| ^~~~~~~ :5:71: note: in passing argument 1 of 'void EigenRefFunction(const
std::vector<Eigen::RefEigen::VectorXd, std::allocator<Eigen::RefEigen::VectorXd> >&)'
5 | void EigenRefFunction(const std::vector<Eigen::RefEigen::VectorXd>& vec)
错误原因
虽然单个Eigen::Map<Eigen::VectorXd>可以隐式转换为Eigen::Ref<Eigen::VectorXd>,但std::vector<Eigen::Map<...>>和std::vector<Eigen::Ref<...>>是完全不同的容器类型,编译器无法自动将整个容器进行隐式转换。容器的模板参数不同,不存在直接的类型兼容关系。
解决方案
方法1:构造临时容器传递(已验证可行)
调用函数时,使用初始化列表构造临时的std::vector<Eigen::Ref<Eigen::VectorXd>>,利用单个元素的隐式转换完成容器构造:
EigenRefFunction({ vec_map.begin(), vec_map.end() });
由于Eigen::Ref是轻量级的引用包装,仅存储指针和尺寸信息,临时容器的拷贝开销可以忽略不计。
方法2:修改函数为模板(更通用)
如果不想构造临时容器,可以将函数改为模板函数,接收任意包含可转换为Eigen::Ref<Eigen::VectorXd>元素的容器:
#include <iostream> #include <vector> #include <Eigen/Core> template<typename Container> void EigenRefFunction(const Container& vec) { for(size_t i=0; i<vec.size(); ++i) { const Eigen::Ref<const Eigen::VectorXd> ref_vec = vec[i]; for(int j=0; j<ref_vec.rows(); ++j) { std::cout << i << ",j: " << ref_vec(j) << std::endl; } } } int main() { std::vector<double> vec1(10, 1.0); std::vector<Eigen::Map<Eigen::VectorXd>> vec_map; vec_map.push_back(Eigen::Map<Eigen::VectorXd>(vec1.data(), vec1.size())); // 直接传入原容器即可 EigenRefFunction(vec_map); }
这种方式不需要任何容器转换,兼容性更强,同时保留了Eigen::Ref的轻量级特性。
替代存储方案
如果需要长期存储多个动态大小的映射向量,除了std::vector<Eigen::Map<Eigen::VectorXd>>,还可以考虑:
std::vector<std::pair<double*, int>>:直接存储数据指针和尺寸,手动管理映射,开销最小,但需要确保原数据生命周期大于该容器。std::vector<Eigen::VectorXd>:如果允许拷贝原数据,直接存储Eigen向量,但会带来内存拷贝开销,适合数据量不大的场景。
内容的提问来源于stack exchange,提问作者rrofa

