【问题标题】:Boost.Python did not match signature lvalueBoost.Python 与签名左值不匹配
【发布时间】:2017-09-07 01:50:49
【问题描述】:

我有一个类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})
>>> 

这个错误是什么意思?显然签名匹配!我怎样才能解决这个问题?

【问题讨论】:

    标签: c++ boost-python


    【解决方案1】:

    问题是,如果您仔细检查 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 它可以做到这一点。问题最终源于&amp;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() 并且一切正常。

    【讨论】:

      猜你喜欢
      • 2023-03-26
      • 2021-02-04
      • 2023-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-23
      相关资源
      最近更新 更多