Использование coeffRef с const CwiseUnaryView - Ошибка при умножении двух CWiseUnaryViews - PullRequest
2 голосов
/ 17 июня 2019

У меня возникают некоторые проблемы при использовании coeffRef() с функцией CWiseUnaryView, но только когда функция объявлена ​​как const

Воспроизводимый пример:

#include <Eigen/Core>

struct dummy_Op {
  EIGEN_EMPTY_STRUCT_CTOR(dummy_Op)
  EIGEN_DEVICE_FUNC
  EIGEN_STRONG_INLINE const double& 
    operator()(const double &v) const { return v; }
  EIGEN_DEVICE_FUNC
  EIGEN_STRONG_INLINE double& 
    operator()(double &v) const { return v; }
};

void foo(Eigen::MatrixXd &out)
{
    //Compiles
    Eigen::CwiseUnaryView<dummy_Op, Eigen::MatrixXd> view(out);
    view.coeffRef(0,0);

    //Doesn't Compile
    const Eigen::CwiseUnaryView<dummy_Op, Eigen::MatrixXd> const_view(out);
    const_view.coeffRef(0,0);
}

Возвращает:

<source>: In function 'void foo(Eigen::MatrixXd&)':
<source>:21:28: error: passing 'const Eigen::CwiseUnaryView<dummy_Op, 
Eigen::Matrix<double, -1, -1> >' as 'this' argument discards qualifiers 
[-fpermissive]

     const_view.coeffRef(0,0);

                            ^

In file included from /opt/compiler-explorer/libs/eigen/v3.3.4/Eigen/Core:413,
                 from <source>:1:
/opt/compiler-explorer/libs/eigen/v3.3.4/Eigen/src/Core/DenseCoeffsBase.h:340:33: note:   
in call to 'Eigen::DenseCoeffsBase<Derived, 1>::Scalar& 
Eigen::DenseCoeffsBase<Derived, 1>::coeffRef(Eigen::Index, Eigen::Index) 
[with Derived = Eigen::CwiseUnaryView<dummy_Op, Eigen::Matrix<double, 
-1, -1> >; Eigen::DenseCoeffsBase<Derived, 1>::Scalar = double; Eigen::Index = long int]'

     EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col)

                                 ^~~~~~~~

Compiler returned: 1

Проводник компилятора: https://godbolt.org/z/kPHPuC

Побочным эффектом этого является то, что умножение двух (неконстантных) CWiseUnaryViews также не выполняется, см. Пример здесь: https://godbolt.org/z/JYQb3d

Ответы [ 2 ]

2 голосов
/ 19 июня 2019

CwiseUnaryView предназначен для использования в качестве выражения L-значения, например,

MatrixXcd A;
A.real() = something; // `A.real()` is writable

Если вы хотите применить поэлементный функтор и использовать его в качестве значения R, вам следуетиспользуйте CwiseUnaryOp вместо:

void foo(Eigen::MatrixXd &out)
{
    Eigen::CwiseUnaryOp<dummy_Op, Eigen::MatrixXd> view1(out);
    // shorter:
    auto view2 = out.unaryExpr(dummy_Op());

    Eigen::MatrixXd result = view1 * view2;
    // or directly write: out.unaryExpr(dummy_Op()) * out.unaryExpr(dummy_Op());
}
2 голосов
/ 18 июня 2019

Суть в том, что вы вызываете неконстантный метод постоянного экземпляра. (Первый) coeffRef, который вызывается, является единственным (и единственным) в DenseCoeffsBase.h (DenseCoeffsBase<Derived, WriteAccessors>), который не является константным. Класс DenseCoeffsBase<Derived, ReadOnlyAccessors> не имеет метода coeffRef. Вы можете обойти эту ошибку (и получить предупреждение), если включите флаг компилятора -fpermissive.

В плотном случае вы, вероятно, все равно захотите использовать метод operator()(Index, Index), который имеет квалифицированную версию const. Я только заметил, что документация явно говорит о том, чтобы использовать этот метод в любом случае, даже для неконстантной версии. Это, очевидно, не вернет константную ссылку, но, по крайней мере, в вашем примере как double, это не должно иметь большого значения.

...