用 Boost.Python 包装 Eigen 的 operator()() 时的重载分辨率
Overload resolution of Eigen's operator()() when wrapping it with Boost.Python
我正在使用 Boost.Python 包装 C++ 库。其中一些函数return 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()))
// ...
;
问题是我不知道函数的正确签名是什么。 "Operationally" 它应该采用两个整数索引和 return 一个双精度值。然而,
typedef const double& (Eigen::MatrixXd::*parop_signature)(int, int) const;
导致如下编译错误(Mac OS X, clang++ in C++11 mode, 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)
”一样简单?任何提示将不胜感激。
错误似乎源于 Eigen::Index
不是 int
,而是默认为 ptrdiff_t
。仅仅因为 int
可以隐式转换为 Eigen::Index
并不意味着您可以将需要 Eigen::Index
的函数指针转换为需要 int
的函数指针。如果可能的话,您最终会在堆栈中传递错误大小的整数。
附录:如果你真的更喜欢 int
而不是 ptrdiff_t
,你可以在包含 Eigen 之前定义 EIGEN_DEFAULT_DENSE_INDEX_TYPE
到 int
,as documented here,请注意这会破坏 ABI 兼容性。
非常感谢@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;
第二部分,必须定义适当的 return 政策。我们想使用由 operator()()
编辑的 const double&
return,因此策略将是 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 正确调用。
我正在使用 Boost.Python 包装 C++ 库。其中一些函数return 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()))
// ...
;
问题是我不知道函数的正确签名是什么。 "Operationally" 它应该采用两个整数索引和 return 一个双精度值。然而,
typedef const double& (Eigen::MatrixXd::*parop_signature)(int, int) const;
导致如下编译错误(Mac OS X, clang++ in C++11 mode, 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)
”一样简单?任何提示将不胜感激。
错误似乎源于 Eigen::Index
不是 int
,而是默认为 ptrdiff_t
。仅仅因为 int
可以隐式转换为 Eigen::Index
并不意味着您可以将需要 Eigen::Index
的函数指针转换为需要 int
的函数指针。如果可能的话,您最终会在堆栈中传递错误大小的整数。
附录:如果你真的更喜欢 int
而不是 ptrdiff_t
,你可以在包含 Eigen 之前定义 EIGEN_DEFAULT_DENSE_INDEX_TYPE
到 int
,as documented here,请注意这会破坏 ABI 兼容性。
非常感谢@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;
第二部分,必须定义适当的 return 政策。我们想使用由 operator()()
编辑的 const double&
return,因此策略将是 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 正确调用。