mar*_*man 5 c++ templates typedef matrix eigen
我正在 Eigen 之上为我的个人代码库编写一个小型线性代数实用程序库。为了使其尽可能灵活,我定义了不同的特征矩阵类型作为参数。然而,我一直遇到的一个问题是,当我使用它时,我无法将固定大小(即在编译时设置)矩阵作为参数传递给具有动态大小(在运行时设置)的函数) 矩阵 typedef 作为参数。我可以理解相反的情况——由于编译时检查,无法将动态大小的矩阵作为固定的矩阵传递,但这似乎应该可行。
\n\n下面的函数是一个可测试的示例pdist2(它确实应该在 Eigen API 中具有本机实现)。
#include <Eigen/Core>\n\nnamespace Eigen\n{\n template <typename T>\n using MatrixXT = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>;\n}\n\n// X is M x N\n// Y is M x K\n// Output is N x K\ntemplate <typename T>\ninline Eigen::MatrixXT<T> pdist2(const Eigen::MatrixXT<T> &X, const Eigen::MatrixXT<T> &Y)\n{\n // ASSERT(X.rows() == Y.rows(), "Input observations must have same number of rows (" + \n // std::to_string(X.rows()) + "!=" + std::to_string(Y.rows()) + ")");\n\n Eigen::MatrixXT<T> dists = X.colwise().squaredNorm().transpose() * Eigen::MatrixXT<T>::Ones(1, Y.cols()) +\n Eigen::MatrixXT<T>::Ones(X.cols(), 1) * Y.colwise().squaredNorm() -\n 2 * X.transpose() * Y;\n\n return dists;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n此代码无法编译:
\n\nEigen::Matrix<double, 3, 5> X;\nX << 8.147236863931790, 9.133758561390193, 2.784982188670484, 9.648885351992766, 9.571669482429456,\n 9.057919370756192, 6.323592462254095, 5.468815192049838, 1.576130816775483, 4.853756487228412,\n 1.269868162935061, 0.975404049994095, 9.575068354342976, 9.705927817606156, 8.002804688888002;\n\nEigen::Matrix<double, 3, 4> Y;\nY << 1.418863386272153, 7.922073295595544, 0.357116785741896, 6.787351548577734,\n 4.217612826262750, 9.594924263929030, 8.491293058687772, 7.577401305783335,\n 9.157355251890671, 6.557406991565868, 9.339932477575505, 7.431324681249162;\n\nEigen::Matrix<double, 5, 4> D = pdist2(X, Y);\nRun Code Online (Sandbox Code Playgroud)\n\n上面的函数已经过单元测试并且计算正确,但只有当X和Y是Eigen::MatrixXd类型时它才会工作。看来一定是我的模板 typedef 导致了问题,但它只是一个具有模板化类型的动态(即在运行时)大小的矩阵。
错误如下:
\n\nerror: no matching function for call to \xe2\x80\x98pdist2(Eigen::Matrix<double, 3, 5>&, Eigen::Matrix<double, 3, 4>&)\xe2\x80\x99\n Eigen::Matrix<double, 5, 4> D = Util::Math::pdist2(X, Y);\n ^\nnote: candidate: template<class T> Eigen::MatrixXT<T> Util::Math::pdist2(Eigen::MatrixXT<T>&, Eigen::MatrixXT<T>&)\n inline Eigen::MatrixXT<T> pdist2(const Eigen::MatrixXT<T> &X, const Eigen::MatrixXT<T> &Y)\n ^\nnote: template argument deduction/substitution failed:\nnote: template argument \xe2\x80\x983\xe2\x80\x99 does not match \xe2\x80\x98#\xe2\x80\x98integer_cst\xe2\x80\x99 not supported by dump_decl#<declaration error>\xe2\x80\x99\n Eigen::Matrix<double, 5, 4> D_est = Util::Math::pdist2(X, Y);\n ^\nnote: \xe2\x80\x98Eigen::Matrix<double, 3, 5>\xe2\x80\x99 is not derived from \xe2\x80\x98Eigen::MatrixXT<T>\xe2\x80\x99\nRun Code Online (Sandbox Code Playgroud)\n\n为什么这不起作用?或者更具体地说,我如何使用模板化的 typedef来确保我的固定大小矩阵确实派生自Eigen::MatrixXT<T>?
注意:这都是使用 Eigen 3.3.3。
\n问题是Matrix<double, 3, 5>和MatrixXT<double>不是同一类型,因此,将前者传递给的唯一方法pdist2是将其转换为MatrixXT<double>. pdist2如果不是模板函数,这将由编译器自动完成:
MatrixXT<double> pdist2(const MatrixXT<double>&,const MatrixXT<double>&);
Run Code Online (Sandbox Code Playgroud)
但由于 pdist2 是模板化的并且不是MatrixXT<double>的基类Matrix<double, 3, 5>,因此在 C++ 中不允许编译器自动推导模板参数来实例化 pdist2。您的解决方案是进一步概括您的函数以将任何内容MatrixBase<>作为输入:
template<typename D1,typename D2>
Matrix<typename D1::Scalar,D1::ColsAtCompileTime,D2::ColsAtCompileTime>
pdist2(const MatrixBase<D1>& _X,const MatrixBase<D2>& _Y);
Run Code Online (Sandbox Code Playgroud)
由于 X 和 Y 将被多次使用,并且它们现在可以是任意表达式(包括昂贵的矩阵乘积),因此您可能希望让 Eigen 在需要时评估参数,为此,您可以使用Ref:
Ref<const typename D1::PlainObject> X(_X);
Ref<const typename D2::PlainObject> Y(_Y);
Run Code Online (Sandbox Code Playgroud)
这样,如果 X 不能表示为指向实际值的指针+跨度,则将对其求值。
| 归档时间: |
|
| 查看次数: |
2734 次 |
| 最近记录: |