使用Boost.Python

时间:2016-09-25 10:37:01

标签: c++ c++11 eigen boost-python

我正在使用Boost.Python包装C ++库。其中的一些函数返回Eigen::MatrixXd个对象(dynamically sized double-precision matrix class)。在Python方面,我只需要访问矩阵的维度,这很容易,并使用Eigen的重载operator()()方法检索一些矩阵元素。不幸的是,有4个这样的重载方法,一个必须手动选择正确的方法,即给Boost.Python一个带有正确签名的函数指针typedef,这就行了

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()))
        // ...
;

问题是我无法弄清楚函数的正确签名是什么。 “操作上”它应该采用两个整数索引并返回一个double值。但是,

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

导致以下编译错误(Mac OS X,C ++ 11模式下的clang ++,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)”一样简单?任何提示都会非常感激。

2 个答案:

答案 0 :(得分:1)

似乎错误源于Eigen::Index不是int但默认为ptrdiff_t的事实。仅仅因为int可以隐式地强制转换为Eigen::Index并不意味着您可以将需要Eigen::Index的函数指针强制转换为需要int的函数指针。如果可能的话,你最终会在堆栈上传递大小错误的整数。

附录:如果您真的更喜欢int而不是ptrdiff_t,则可以在包含Eigen as documented here之前将EIGEN_DEFAULT_DENSE_INDEX_TYPE定义为int,请注意这将是var http = require('http'); http.createServer().listen(3000, '127.0.0.1'); 打破ABI兼容性。

答案 1 :(得分:0)

非常感谢@xao和@chtz的帮助。作为参考(双关语)我在这里展示了最终有效的解决方案。

第一部分,Eigen括号运算符的签名,用于访问矩阵元素:

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

第二部分,必须定义适当的退货政策。我们希望使用const double&返回的operator()(),因此政策将为copy_const_reference

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调用。