🎃

Eigenで型の違いに惑わされた話

2023/03/11に公開約2,600字

問題発生

Eigenでベクトルや行列の演算を記述していたところ,いきなり以下のコンパイルエラーが出てきて目が回りました。

/usr/include/eigen3/Eigen/src/Core/AssignEvaluator.h: In instantiation of ‘void Eigen::internal::call_assignment_no_alias(Dst&, const Src&, const Func&) [with Dst = Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<double>, Eigen::Matrix<double, -1, 1> >; Src = Eigen::CwiseBinaryOp<Eigen::internal::scalar_product_op<double, double>, const Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<double>, const Eigen::Matrix<double, -1, 1> >, const Eigen::Matrix<double, -1, 1> >; Func = Eigen::internal::add_assign_op<double, double>]’:
/usr/include/eigen3/Eigen/src/Core/AssignEvaluator.h:858:27:   required from ‘void Eigen::internal::call_assignment(Dst&, const Src&, const Func&, typename Eigen::internal::enable_if<(! Eigen::internal::evaluator_assume_aliasing<Src>::value), void*>::type) [with Dst = Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<double>, Eigen::Matrix<double, -1, 1> >; Src = Eigen::CwiseBinaryOp<Eigen::internal::scalar_product_op<double, double>, const Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<double>, const Eigen::Matrix<double, -1, 1> >, const Eigen::Matrix<double, -1, 1> >; Func = Eigen::internal::add_assign_op<double, double>; typename Eigen::internal::enable_if<(! Eigen::internal::evaluator_assume_aliasing<Src>::value), void*>::type = void*; typename Eigen::internal::evaluator_traits<SrcXprType>::Shape = Eigen::DenseShape]’
/usr/include/eigen3/Eigen/src/Core/CwiseBinaryOp.h:177:18:   required from ‘Derived& Eigen::MatrixBase<Derived>::operator+=(const Eigen::MatrixBase<OtherDerived>&) [with OtherDerived = Eigen::CwiseBinaryOp<Eigen::internal::scalar_product_op<double, double>, const Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<double>, const Eigen::Matrix<double, -1, 1> >, const Eigen::Matrix<double, -1, 1> >; Derived = Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<double>, Eigen::Matrix<double, -1, 1> >]’

ぐふぅ。。雰囲気的には演算子が定義されてない感じのメッセージです。
さっきまでコンパイル通ってたのに何で?のパターンでした。

該当コードは次のような部分です。

auto x = VectorXd::Zero(L);
for (int i = 0; i < N; i++)
{
  x += y;  // y: VectorXd型の変数
}

原因

しばらく悶絶していましたが,xの型を調べると次のようになっていることがわかりました。

Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<double>, Eigen::VectorXd>

VectorXd::Zero()の戻り値がこれだったようで,こいつが"+=なんて演算子持ってないぞ!"と怒っていたわけです。

というわけで次のように書き直すと無事コンパイルが通りました。

- auto x = VectorXd::Zero(L);
+ VectorXd x = VectorXd::Zero(L);
for (int i = 0; i < N; i++)
{
  x += y;  // y: VectorXd型の変数
}

イキってautoばかり使ってましたが,行列でごちゃごちゃやってるとVectorだかMatrixだがもわからなくなるので,ちゃんと型を書いた方がいいですね。
OpenCVのMatもそうですが,計算過程で型が微妙に変わったりもしますので。

結論

軽率なautoは火傷する。

Discussion

ログインするとコメントできます