(boost.python) 暴露重载运算符+() 时出错。 “类型错误:找不到 to_python(按值)转换器”
我是 boost.python 的新手,我收到此错误,我想获得一些帮助。作为一个更大项目的一部分,我正在为我拥有的向量类编写一个包装器。正如您从下面的代码中注意到的那样,此类可以是 2D 或 3D 的,但对于我当前遇到的问题来说没有太大区别。我正在尝试包装我所拥有的向量类中定义的一些运算符,只要函数(或重载运算符)不返回 Vector 类型的“值”,这就可以正常工作,所以我猜 python 不知道什么与我按值返回的对象有关。这是代码:
struct D2
{
//...
typedef Eigen::Matrix< long double, 2, 1 > Vector;
//...
};
struct D3
{
//...
typedef Eigen::Matrix< long double, 3, 1 > Vector;
//...
};
现在定义以下宏来对 2 个可能的维度执行相同的工作,
BOOST_PYTHON_MODULE(types)
{
using namespace boost::python;
#define GPS_PY_EXPOSE_VECTOR(DIM, NAME) \
class_<DIM::Vector>(NAME) \
.def(init<DIM::Vector>()) \
.def("norm", &DIM::Vector::norm) \
.def("__setitem__", &PyVectorHelper<DIM>::setVectorElem) \
.def("__getitem__", &PyVectorHelper<DIM>::getVectorElem) \
.def(self += self) \
.def(self -= self) \
.def(self + self) /*Not working!!!*/ \
.def(self - self) /*Not working!!!*/ \
.def("toStr", &PyVectorHelper<DIM>::toPyString) \
.def("__str__", &PyVectorHelper<DIM>::toStdString) \
;
GPS_PY_EXPOSE_VECTOR(D2, "Vector2D")
GPS_PY_EXPOSE_VECTOR(D3, "Vector3D")
}
上面的代码可以正常工作,除非我尝试在 python 中使用“+”或“-”运算符,如下所示:
>>>import types
>>>v1 = types.Vector2D()
>>>v2 = types.Vector2D()
>>>v3 = v1 + v2 //ERROR!!!
错误是以下:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: No to_python (by-value) converter found for C++ type: Eigen::CwiseBinaryOp<Eigen::internal::scalar_sum_op<long double>, Eigen::Matrix<long double, 2, 1, 0, 2, 1> const, Eigen::Matrix<long double, 2, 1, 0, 2, 1> const>
我按照教程 这里,我在互联网上没有找到与该错误相关的信息。
非常欢迎任何帮助! 提前致谢。
在 Luc Danton 的回答后进行编辑
致 Luc Danton:感谢您的回答,我尝试了您所说的,但它不起作用。这是我得到的错误:
error: no matching function for call to ‘boost::python::class_<Eigen::Matrix<long double, 2, 1, 0, 2, 1>, boost::python::detail::not_specified, boost::python::detail::not_specified, boost::python::detail::not_specified>::def(boost::python::detail::operator_<(boost::python::detail::operator_id)0u, boost::python::self_ns::self_t, boost::python::self_ns::self_t>, boost::python::return_value_policy<boost::python::to_python_value<Eigen::Matrix<long double, 2, 1, 0, 2, 1> >, boost::python::default_call_policies>)’
但是,由于您的评论,我得到了这个想法:编写一个辅助函数来执行加法并转换 Eigen“表达式对象”(这是表示运算符的私有类型)。这是:
template <typename TDim>
struct PyVectorHelper
{
//...
static typename TDim::Vector sum(typename TDim::Vector const &v1, typename TDim::Vector const &v2)
{
return v1 + v2;
}
//...
};
然后
.def("__add__", &PyVectorHelper<DIM>::sum)
这工作正常并且按照我想要的方式进行,因为 PyVectorHelper
返回一个 DIM::Vector
。问题是,几乎每个 Eigen 重载的运算符都会返回一个表达式对象,这意味着我必须为几乎所有运算符实现类似的函数!这既不好也不实用:P。
也许仍然可以使用 return_value_policy
和 to_python_value
这样我就可以避免这种繁琐的运算符重写?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
矩阵/向量库似乎正在使用表达式模板。在这种情况下,正如您所评论的,operator+ 不返回向量,而是返回表示操作的私有类型。返回的值被困在 C++ 方面,并且无法传递给 Python,因为私有类型未注册。
现在我对 Boost.Python 不太熟悉,但我认为你可以用 返回值策略。传递
return_value_policy >
因为策略会强制将返回的类型转换为您已注册的DIM::Vector
。这看起来像:It seems the matrix/vector library is using expression templates. In this case, and as you have remarked,
operator+
is not returning a vector but a private type that represents the operation. The returned value is left trapped on the C++ side of things and can't be passed to Python as the private type is not registered.Now I'm not too familiar with Boost.Python, but I think you can fix your problem with the return value policy. Passing a
return_value_policy<to_python_value<DIM::Vector> >
as policy would force converting the returned type toDIM::Vector
, which you have registered. This would look like: