2016-09-25 6 views
1

Boost.Pythonを使用してC++ライブラリをラッピングする処理中です。その中のいくつかの機能はEigen::MatrixXdオブジェクト(dynamically sized double-precision matrix class)を返します。 Python側では、行列の次元にアクセスするだけで済みます。これは簡単で、Eigenのオーバーロードされたoperator()()メソッドを使っていくつかの行列要素を取得します。残念ながら、そのような4つのオーバーロードメソッドがあり、1は、手動で正しいものを選ぶすなわちBoost.Pythonに正しいシグネチャを持つ関数ポインタのtypedefを与えるために持って、線に沿って何かBoost.Pythonでラップする際のEigenの演算子()()のオーバーロード解決

namespace bpy = boost::python; 
bpy::class_<Eigen::MatrixXd>("MatrixXd", 
     "Variable-size double-precision matrix class", 
     bpy::init<const Eigen::MatrixXd&>() 
    ) 
     .def("__call__", static_cast<parop_signature>(&Eigen::MatrixXd::operator())) 
     // ... 
; 

問題は、私が把握することはできませんということです関数の正しいシグネチャは何か。 「操作上」は、2つの整数インデックスをとり、2倍の値を返す必要があります。しかし、

typedef const double& (Eigen::MatrixXd::*parop_signature)(int, int) const; 

次のコンパイルエラー(マックOS X、打ち鳴らす++でC++ 11モード、Boost.Python V1.61)での結果:十分

address of overloaded function 'operator()' cannot be static_cast to type 
     'const double &(MatrixXd::*)(int, int) const' 
    ...static_cast<const double& (Eigen::MatrixXd::*)(int, int) const>(&Eigen::MatrixXd::operator()) 
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
/usr/local/eigen/current/Eigen/src/Core/DenseCoeffsBase.h:111:41: note: 
     candidate function 
    EIGEN_STRONG_INLINE CoeffReturnType operator()(Index row, Index col) const 
             ^
/usr/local/eigen/current/Eigen/src/Core/DenseCoeffsBase.h:171:5: note: 
     candidate function 
    operator()(Index index) const 
    ^
/usr/local/eigen/current/Eigen/src/Core/DenseCoeffsBase.h:334:5: note: 
     candidate function 
    operator()(Index row, Index col) 
    ^
/usr/local/eigen/current/Eigen/src/Core/DenseCoeffsBase.h:392:5: note: 
     candidate function 
    operator()(Index index) 

フェア、あなたは言うだろうしかし、私はBoost.Pythonにどのように伝えることができないのか分かりません。CoeffReturnTypeは実際にはdoubleです(または、おそらくconst double&)。IndexTypeは終わりに平文に変換されます。 constの修飾子の有無にかかわらず、typedef -sのあらゆる種類の組み合わせを試しました。

はしても、私は
candidate template ignored: couldn't infer template argument '_Tp' 
mem_fn(_Rp _Tp::* __pm) 
^ 

を既に経験してきたし、提供することができます誰かが存在し得る

auto eigen_indexfn = std::mem_fn<double(int,int)>(&Eigen::MatrixXd::operator()); 

、ノー成功のようにC++ 11スタイルの関数ポインタを宣言しようとしました私はすべての目的と目的のための正しい署名が "double Eigen::MatrixXd::operator(int, int)"のように簡単でなければなりませんか?どんなヒントも大歓迎です。

+0

戻り値の型は実際には 'double'ではなく、マトリックス内のその位置に代入することもできる型です。 – Xeo

+0

@xeo:あなたはもっと明示できるでしょうか?あなたは戻り値の型が 'double 'であることを知っていますか?(これはあなたが「マトリックス内のその位置に代入することも可能な型」の意味ですか?)' operator()(Index、Index) '' const''関数は非const宣言ではありませんか? '' const'''も同様に '' const''版ですか?ありがとうございます。 –

+0

@'double&(MatrixXd :: *)(int、int)') –

答えて

1

Eigen::Indexintではありませんが、デフォルトはptrdiff_tです。 intが暗黙的にEigen::Indexにキャストできるからといって、Eigen::Indexを必要とする関数ポインタを、intを必要とする関数ポインタにキャストできるわけではありません。可能であれば、間違ったサイズの整数をスタックに渡すことになります。

補遺:あなたは本当にptrdiff_tintを好む場合は、アイゲン、as documented hereを含む前intEIGEN_DEFAULT_DENSE_INDEX_TYPEを定義することができ、これは、ABIの互換性を壊すことに注意してください。

+0

はい、これは画期的なものでしたが、多くのありがとうございました!しかし、これは完全な話ではありません。正しいものとしてあなたを受け入れる一方で、参考のために以下の回答を追加します。 –

0

@ xaoと@chtzの助けを借りて感謝します。参考のために、ここでは最終的に解決した解決策をコメントとともに示します。

第1部は、行列要素にアクセスするための固有の括弧オペレータの署名:

// const element access in dynamically-sized double matrices 
// note that the Index type is ptrdiff_t 
// and the CoeffReturnType is const double& 
typedef const double& (Eigen::MatrixXd::*parop_signature)(ptrdiff_t,ptrdiff_t) const; 

パート2は、適切なリターンポリシーが定義されなければなりません。私たちは、その政策がcopy_const_referenceなりますoperator()()によって返さconst double&を使用したい:

bpy::class_<Eigen::MatrixXd>("MatrixXd", 
    "Variable-size double-precision matrix class", 
    bpy::init<const Eigen::MatrixXd&>() 
) 
    .def("__call__", static_cast<parop_signature>(&Eigen::MatrixXd::operator()), 
     bpy::return_value_policy<bpy::copy_const_reference>()) 

このすべてを通過した後、それがコンパイルされ、正しくはPythonから呼び出すことができます。

関連する問題