🎃
Eigenで型の違いに惑わされた話
問題発生
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