2016-09-25 24 views
1

我正在使用Boost.Python封裝一個C++庫。其中的一些功能返回Eigen::MatrixXd對象(a dynamically sized double-precision matrix class)。在Python方面,我只需要訪問矩陣的維數,這很容易,並用Eigen的重載operator()()方法檢索一些矩陣元素。不幸的是有4種這樣的重載方法,一個必須手動選擇是正確的,即給予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())) 
     // ... 
; 

的問題是,我無法弄清楚函數的正確簽名是什麼。 「操作上」應該採用兩個整數索引並返回一個雙精度值。然而,

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

導致以下編譯錯誤(Mac 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將在一天結束時解析爲普通的int。我嘗試了各種各樣的typedef -s的組合,有或沒有const限定符。

甚至試圖聲明一個C++ 11式的函數指針像

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

,沒有成功,我得到

candidate template ignored: couldn't infer template argument '_Tp' 
mem_fn(_Rp _Tp::* __pm) 
^ 

是否有別人誰通過這個已經消失,並能提供我對所有意圖和目的的正確簽名應該像「double Eigen::MatrixXd::operator(int, int)」一樣簡單?任何提示將不勝感激。

+0

返回類型實際上不是'double',而是一種類型,它也允許賦值給矩陣內的那個位置。 – Xeo

+0

@xeo:你能更明確嗎?你確實知道返回類型是一個'double&'(我認爲這就是你所說的「一種也允許賦值到矩陣中的那個位置的類型」?你知道'operator()(Index,Index) '函數不是''constst',或者也可能有一個'const'版本?非常感謝。 –

+0

@xeo我又一次:非常量簽名不起作用,我得到「'不能static_cast來鍵入'parop_signature '(又名 'double&(MatrixXd :: *)(int,int)')'「 –

回答

1

看起來錯誤起源於事實Eigen::Index不是int但默認爲ptrdiff_t。僅僅因爲int可以隱式轉換爲Eigen::Index並不意味着您可以投射一個函數指針,該函數指針需要Eigen::Index才能生成需要int的函數指針。如果可能的話,你最終會在堆棧中傳遞大小錯誤的整數。

附錄:如果你真的喜歡intptrdiff_t,你可以包括本徵,as documented here之前定義EIGEN_DEFAULT_DENSE_INDEX_TYPEint,要知道,這將打破ABI兼容性。

+0

是的,這是突破,非常感謝!但這不是完整的故事,我在下面添加一個答案作爲參考,同時接受你的答案爲正確答案。 –

0

非常感謝@xao和@chtz的幫助。作爲參考(雙關意圖),我在這裏展示了最終解決方案,並帶有評論。

一個部分,本徵的括號運營商的訪問矩陣元素簽名:

// 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; 

第二部分,適當的退貨政策必須予以界定。我們希望使用operator()()返回,因此政策將copy_const_referenceconst 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的正確調用。