【问题标题】:eigen template doesn't work with matrices of fixed size特征模板不适用于固定大小的矩阵
【发布时间】:2021-12-23 18:54:16
【问题描述】:

我编写了以下模板来检查三角形是否退化:

template<typename Derived>
bool nondegenerate(const Eigen::PlainObjectBase<Derived>& triangle) {

  typedef typename Derived::Scalar scalarType;

  if (triangle.cols() == 2) {
    Eigen::Matrix<scalarType, 1, 2> v1 = triangle.row(1) - triangle.row(0);
    Eigen::Matrix<scalarType, 1, 2> v2 = triangle.row(2) - triangle.row(0);
    return v1(0)*v2(1) - v1(1)*v2(0);
  } else if (triangle.cols() == 3) {
    Eigen::Matrix<scalarType, 1, 3> v1 = triangle.row(1) - triangle.row(0);
    Eigen::Matrix<scalarType, 1, 3> v2 = triangle.row(2) - triangle.row(0);
    return v1.cross(v2).norm();
  } else {
    std::cerr << "Undefined input." << std::endl;
    return false;
  }
}

如果我用Eigen::MatrixXi 类型的矩阵调用nondegenerate,上面的代码可以正常工作:

Eigen::MatrixXi triangle;
triangle.resize(3,2);
triangle << 1,2,3,4,5,6;
nondegenerate(triangle);

但是,如果我将上面的动态大小矩阵替换为固定大小的矩阵:

Eigen::Matrix<int, 3, 2> triangle;
triangle << 1,2,3,4,5,6;
nondegenerate(triangle);

它报告编译错误:

/usr/local/include/eigen3/Eigen/src/Core/AssignEvaluator.h:833:3: error: static_assert 由于要求而失败 '(int(Eigen::internal::size_of_xpr_at_compile_time<:matrix> >::ret) == 0 && int(Eigen::internal::size_of_xpr_at_compile_time<:cwisebinaryop int>, const Eigen::Block, 1, 2, false>, const Eigen::Block, 1, 2, 假> > >::ret) == 0) || ((int(Matrix::RowsAtCompileTime) == Eigen::Dynamic || int(CwiseBinaryOp<:internal::scalar_difference_op int>, const Eigen::Block, 1, 2, false>, const Eigen::Block, 1, 2, false> >::RowsAtCompileTime) == 特征::动态 || int(Matrix::RowsAtCompileTime) == int(CwiseBinaryOp<:internal::scalar_difference_op int>, const Eigen::Block, 1, 2, false>, const Eigen::Block, 1, 2, false> >::RowsAtCompileTime)) && (int(Matrix::ColsAtCompileTime) == Eigen::Dynamic || int(CwiseBinaryOp<:internal::scalar_difference_op int>, const Eigen::Block, 1, 2, false>, const Eigen::Block, 1, 2, false> >::ColsAtCompileTime) == 特征::动态 || int(Matrix::ColsAtCompileTime) == int(CwiseBinaryOp<:internal::scalar_difference_op int>, const Eigen::Block, 1, 2, false>, const Eigen::Block, 1, 2, false> >::ColsAtCompileTime))) ' “YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES” EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(ActualDstTypeCleaned,Src) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~ /usr/local/include/eigen3/Eigen/src/Core/util/StaticAssert.h:190:3:注意:从宏扩展 'EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE' EIGEN_STATIC_ASSERT(
^~~~~~~~~~~~~~~~~~~~~~ /usr/local/include/eigen3/Eigen/src/Core/util/StaticAssert.h:33:40:注意:从宏“EIGEN_STATIC_ASSERT”扩展 #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG); ^ ~ /usr/local/include/eigen3/Eigen/src/Core/PlainObjectBase.h:732:17:注意:在函数模板特化的实例化中 'Eigen::internal::call_assignment_no_alias<:matrix>, Eigen::CwiseBinaryOp<:internal::scalar_difference_op int>, const Eigen::Block, 1, 2, false>, const Eigen::Block, 1, 2, false> >, Eigen::internal::assign_op >' 在这里请求 internal::call_assignment_no_alias(this->derived(), other.derived(), internal::assign_op >::_set_noalias<:cwisebinaryop int>, const Eigen::Block, 1, 2, false>, const Eigen::Block, 1、2、假> > >' 在这里请求 _set_noalias(其他); ^ /usr/local/include/eigen3/Eigen/src/Core/Matrix.h:377:9:注意:在函数模板特化的实例化中 'Eigen::PlainObjectBase<:matrix> >::PlainObjectBase<:cwisebinaryop int>, const Eigen::Block, 1, 2, false>, const Eigen::Block, 1、2、假> > >' 在这里请求 :基础(其他。派生()) ^ testEigenIgl.cpp:1052:42: 注意:在函数模板特化的实例化中'Eigen::Matrix::Matrix<:cwisebinaryop int>, const Eigen::Block, 1, 2, false>, const Eigen::Block, 1、2、假> > >' 在这里请求 Eigen::Matrix v1 = triangle.row(1) - triangle.row(0); ^ testEigenIgl.cpp:1082:7: 注意:在函数模板特化的实例化中'nondegenerate<:matrix> >' 在这里请求

如何修复模板以同时接受动态和固定大小的矩阵?

谢谢!

【问题讨论】:

  • 您应该确定矩阵的大小是否是静态的,并在这种情况下使用if constexpr。如果您使用C++14 或更早的版本,那么您应该使用基于 SFINAE 的技术并针对不同情况重载该方法。

标签: c++ templates matrix eigen


【解决方案1】:

您遇到的问题是您的第一个 if 的两个分支都必须有效,并且在固定大小矩阵的情况下,至少一个分支不是,因为您为结果指定了确切的尺寸算术。

template<typename Derived>
bool nondegenerate(const Eigen::PlainObjectBase<Derived>& triangle) {

  typedef typename Derived::Scalar scalarType;

  if (triangle.cols() == 2) {
    auto v1 = triangle.row(1) - triangle.row(0);
    auto v2 = triangle.row(2) - triangle.row(0);
    return v1(0)*v2(1) - v1(1)*v2(0);
  } else if (triangle.cols() == 3) {
    auto v1 = triangle.row(1) - triangle.row(0);
    auto v2 = triangle.row(2) - triangle.row(0);
    return v1.cross(v2).norm();
  } else {
    std::cerr << "Undefined input." << std::endl;
    return false;
  }
}

除此之外:有一些通用公式可以找到任何大小的方阵的行列式,为什么不使用其中一种方法呢?

【讨论】:

  • 您可以将v1v2 的计算移出if 分支。不过,在将 auto 与 Eigen 表达式一起使用时,您总是需要小心。我觉得这个案子没问题,但我没有验证...
  • @chtz 你可能可以,但如果你传递了一个空矩阵或 1 × 1 矩阵,那就会中断
  • 是的......可能,我会在此之前从无效案例中分支出来(但这也会增加代码大小......)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-19
  • 2013-02-13
  • 2020-09-04
相关资源
最近更新 更多