我有一个类 Foo
,它有一个我想公开的成员 x
,但是通过 getter 函数而不是属性。我刚刚发现 make_getter
,所以我想我会试一试:
#include <boost/python.hpp>
namespace py = boost::python;
struct Base {
int x;
};
struct Foo : Base {
Foo(int i): Base{i} { }
};
BOOST_PYTHON_MODULE(Foo)
{
py::class_<Foo>("Foo", py::init<int>())
.def_readonly("x", &Foo::x)
.def("getX", py::make_getter(&Foo::x))
;
}
然而,这失败了:
>>> import Foo
>>> f = Foo.Foo(42)
>>> f.x
42
>>> f.getX()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
Foo.getX(Foo)
did not match C++ signature:
getX(Base {lvalue})
>>>
这个错误到底是什么意思?显然签名匹配!我怎样才能解决这个问题?
最佳答案
问题是,如果您仔细检查 ArgumentError
异常,您正在使用 Foo
调用 getX()
:
>>> f.getX()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
Foo.getX(Foo)
而您尝试访问的数据成员实际上是 Base
的成员:
did not match C++ signature:
getX(Base {lvalue})
Boost.Python 需要执行从左值 Foo
到左值 Base
的转换,而您实际上并没有告诉 Boost 它可以做到这一点。问题最终源于 &Base::x
是 int Base::*
而不是 int Foo::*
,所以boost::python::make_getter
中的模板推导生成了一个采用 Base
而不是 Foo
的函数。
最简单的解决方案是确保将正确的指向成员的指针传递给 make_getter
:
BOOST_PYTHON_MODULE(Foo)
{
py::class_<Foo>("Foo", py::init<int>())
.def_readonly("x", &Foo::x)
.def("getX", py::make_getter(static_cast<int Foo::*>(&Foo::x)))
;
}
有了这个类型转换,一切正常:
>>> from Foo import Foo
>>> Foo(4).getX()
4
虽然这有点乏味,所以您可以编写一个快速方法/宏来为您完成:
template <typename Derived, typename Base, typename T>
T Derived::* as_derived(T Base::*member) {
return static_cast<T Derived::*>(member);
}
#define AS_DERIVED(CLS, FIELD) as_derived<CLS>(&CLS::FIELD)
你可以用它来做:
BOOST_PYTHON_MODULE(Foo)
{
py::class_<Foo>("Foo", py::init<int>())
.def_readonly("x", &Foo::x)
.def("getX", py::make_getter(AS_DERIVED(Foo, x)))
;
}
或者,您可以直接告诉 Boost.Python 层次结构:
BOOST_PYTHON_MODULE(Foo)
{
py::class_<Base>("Base", py::no_init)
.def("getX", py::make_getter(&Base::x))
;
py::class_<Foo, py::bases<Base>>("Foo", py::init<int>())
.def_readonly("x", &Foo::x)
;
}
这样,Foo
继承了 getX()
,一切都很好。
关于c++ - Boost.Python 与签名左值不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30791975/