【问题标题】:boost.python: Argument types did not match C++ signatureboost.python:参数类型与 C++ 签名不匹配
【发布时间】:2023-03-26 22:08:02
【问题描述】:

我在 python 中调用 C++ 函数时遇到了一个奇怪的问题。

我公开了一个我想从中调用函数的类:

class_<MyClass, std::shared_ptr<MyClass>>("MyClass", init<>())
    // ...
    .def("someFunc", &MyClass::someFunc)
;

我从另一个通过.def_readonly(...)公开的类的成员变量中获得std::shared_ptr&lt;MyClass&gt;

当我尝试调用该函数时,我收到以下错误:

File "pytest.py", line 27, in test_func
    cu.someFunc("string")
Boost.Python.ArgumentError: Python argument types in
    MyClass.someFunc(MyClass, str)
did not match C++ signature:
    result(MyClass{lvalue}, std::string)

据我所知,签名 确实 匹配。 有人看到问题了吗?

【问题讨论】:

    标签: c++ python boost c++11 boost-python


    【解决方案1】:

    正如ticket 中所跟踪,Boost.Python 不完全支持std::shared_ptr

    简而言之,有两种简单的解决方案:


    虽然异常中的签名看起来相同,但微妙的细节是 Python MyClass 对象嵌入了 std::shared_ptr&lt;MyClass&gt;。因此,Boost.Python 必须执行从 std::shared_ptr&lt;MyClass&gt; 到左值 MyClass 的转换。但是,Boost.Python 目前不支持custom lvalue conversions。因此,会引发 ArgumentError 异常。

    当用def_readonly("spam", &amp;Factory::spam)暴露成员变量时,相当于通过:

    add_property("spam", make_getter(&Factory::spam, return_internal_reference()))
    

    当以这种方式公开的类型是boost::shared_ptr 时,Boost.Python 有特殊代码。因为它是一个只读属性,并且std::shared_ptr 打算被复制,所以使用return_by_value 类型的返回值策略公开std::shared_ptr 的副本是安全的。

    这是一个完整的示例,其中Factory 公开了由std::shared_ptr 持有的Spam 对象和由boost::shared_ptr 持有的Egg 对象:

    #include <iostream>
    #include <memory> // std::shared_ptr, std::make_shared
    #include <string>
    #include <boost/make_shared.hpp>
    #include <boost/shared_ptr.hpp>
    #include <boost/python.hpp>
    
    /// @brief Mockup Spam type.
    struct Spam
    {
      ~Spam() { std::cout << "~Spam()" << std::endl; }
    
      void someFunc(std::string str)
      {
        std::cout << "Spam::someFunc() " << this << " : " << str << std::endl;
      }
    };
    
    /// @brief Mockup Egg type.
    struct Egg
    {
      ~Egg() { std::cout << "~Egg()" << std::endl; }
    
      void someFunc(std::string str)
      {
        std::cout << "Egg::someFunc() " << this << " : " << str << std::endl;
      }
    };
    
    /// @brief Mockup Factory type.
    struct Factory
    {
      Factory()
        : spam(std::make_shared<Spam>()),
          egg(boost::make_shared<Egg>())
      {
        spam->someFunc("factory");
        egg->someFunc("factory");
      }
    
      std::shared_ptr<Spam>   spam;
      boost::shared_ptr<Egg>  egg;
    };
    
    BOOST_PYTHON_MODULE(example)
    {
      namespace python = boost::python;
    
      // Expose Factory class and its member variables.
      python::class_<Factory>("Factory")
        // std::shared_ptr<Spam>
        .add_property("spam", python::make_getter(&Factory::spam,
            python::return_value_policy<python::return_by_value>()))
        // boost::shared_ptr<Egg>
        .def_readonly("egg", &Factory::egg)
        ;
    
      // Expose Spam as being held by std::shared_ptr.
      python::class_<Spam, std::shared_ptr<Spam>>("Spam")
        .def("someFunc", &Spam::someFunc)
        ;
    
      // Expose Egg as being held by boost::shared_ptr.
      python::class_<Egg, boost::shared_ptr<Egg>>("Egg")
        .def("someFunc", &Egg::someFunc)
        ;
    }
    

    交互式 Python 演示用法和对象生命周期:

    >>> import example
    >>> factory = example.Factory()
    Spam::someFunc() 0x8d73250 : factory
    Egg::someFunc() 0x8d5dbc9 : factory
    >>> factory.spam.someFunc("python")
    Spam::someFunc() 0x8d73250 : python
    >>> factory.egg.someFunc("python")
    Egg::someFunc() 0x8d5dbc9 : python
    >>> factory = None
    ~Egg()
    ~Spam()
    >>> factory = example.Factory()
    Spam::someFunc() 0x8d73250 : factory
    Egg::someFunc() 0x8d06569 : factory
    >>> spam = factory.spam
    >>> factory = None
    ~Egg()
    >>> spam.someFunc("python")
    Spam::someFunc() 0x8d73250 : python
    >>> spam = None
    ~Spam()
    >>> factory = example.Factory()
    Spam::someFunc() 0x8d73250 : factory
    Egg::someFunc() 0x8ce10f9 : factory
    >>> egg = factory.egg
    >>> factory = None
    ~Spam()
    >>> egg.someFunc("python")
    Egg::someFunc() 0x8ce10f9 : python
    >>> egg = None
    ~Egg()
    

    【讨论】:

      【解决方案2】:

      还没有测试过,但这可能有效:

      boost::python::register_ptr_to_python<std::shared_ptr<MyClass>>();
      

      来源: http://www.boost.org/doc/libs/1_55_0/libs/python/doc/v2/register_ptr_to_python.html

      【讨论】:

        猜你喜欢
        • 2021-02-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-19
        • 2018-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多