c++ - Boost.Python 与签名左值不匹配

标签 c++ boost-python

我有一个类 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::xint 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/

相关文章:

c++ - C 文件* 到 ostream/istream

c++ - 使用 Boost Python & std::shared_ptr

c++ - 将 boost::asio::ip::address operator == 导出到 python

c++ - 使用 boost.python 将类暴露给 python 时出现构建错误

python - 如何在 Windows 7 上安装 Boost.Python 以安装 python 包?

c++ - 0xC00000005 未实例化指针错误

C++输出流运算符<<()中的字符何时加宽?

c++ - 在 CreateProcess 之后调用 GetModuleFileNameEx 时出现 ERROR_INVALID_HANDLE

c++ - 生产中可选的非终端

cmake - 无法在 OS X 上链接 Boost.Python