しゃけのブログ

某大学院で研究している人の備忘録

ユーザ型をEigen::Matrixへ変換するoperatorがうまく働かない

問題

次のようなコードを書いた.

ubuntu 16.04

struct pose
{
    explicit operator Eigen::Matrix4f () const
    {
            Eigen::Translation3f translation(x, y, z);
            Eigen::AngleAxisf rotation_x(roll, Eigen::Vector3f::UnitX());
            Eigen::AngleAxisf rotation_y(pitch, Eigen::Vector3f::UnitY());
            Eigen::AngleAxisf rotation_z(yaw, Eigen::Vector3f::UnitZ());

            return (translation * rotation_z * rotation_y * rotation_x).matrix();
    }
};

姿勢情報(x,y,z,roll,pitch,yaw) を剛体変換行列へ変換するoperatorを実装したのだが,思ったように使えなかった.

pose p;
auto m = static_cast<Eigen::Matrix4f>(p); // compile error!!!

error: no matching function for call to 'Eigen::Matrix::_init1(const pose&)'

EigenのMatrixはコンストラクタによる初期化じゃなくてinitっていう関数へ置き換えられている...? それが何らかの理由でoperatorの呼び出し優先度よりも高くなってしまっているみたい.

理由

https://forum.kde.org/viewtopic.php?f=74&t=137768

Eigenのバージョン3.3では,Eigen::Matrixについて次のようなコンストラクタが定義されているみたい.

template <typename T> explicit Matrix(const T& x) {...}

これによって static_cast<Eigen::Matrix4f>(p) に対応する呼び出しがこのコンストラクタになってしまう.

解決策1(バージョン変更)

c++ - Conversion operator in Eigen - Stack Overflow

どうやらバージョンの問題らしい.

ubuntu 16.04でインストールしたもののバージョンが3.2.92だったが,3.2.6を使うとよいらしい.

解決策2 (明示的なキャストをやめる)

Eigen::Matrix4f m = p;

こうすると,operatorの方がきちんと呼ばれる.ただし,explicitは外しておく必要がある.

struct pose
{
    operator Eigen::Matrix4f () const {...}
};

しかし文法が変わってしまうので,テンプレートパラメータとしてEigen::Matrix4fを渡したときに少し困る. これは,Eigen用の特殊化をするか,Eigen Matrix自体をラップするラッパークラスを作るような解決策が考えられる.