【问题标题】:boost::python how to use function member as python callbackboost::python 如何使用函数成员作为python回调
【发布时间】:2020-11-14 02:51:35
【问题描述】:

我想在我的 c++ 应用程序上使用这个 python 模块:https://python-omxplayer-wrapper.readthedocs.io/en/latest/

它是一个 omxplayer python 包装器,并且有一些我想链接到我的 c++ 类函数成员的回调事件。

我使用这样的静态函数成功地做到了:

void foo(py::object player) { 
    std::cout << "pause event callback" << std::endl; 
}

py::object mod = py::import("omxplayer.player");

OMXPlayer::pyOMXPlayer = mod.attr("OMXPlayer")(_file, args, NULL, NULL, _dbus_name, _pause);

OMXPlayer::pyOMXPlayer.attr("pauseEvent") = py::make_function( &foo );

OMXPlayer 是我的 c++ 类。

我尝试使用 boost::bind 和 boost::function 没有成功。

如何使用OMXPlayer::onPause()函数代替static foo函数?

用例子编辑:

OMXPlayer.cpp

    #include "OMXPlayer.h"
    OMXPlayer::OMXPlayer(std::string _file, 
        std::vector<std::string> _args, 
        bool _pause, 
        std::string _dbus_name){
    
    
    try{
        Py_Initialize();
        py::object mod = py::import("omxplayer.player");
        
        
        py::list args;
        for(auto const& value: _args) {
            args.append(value);
        }
        
        

        OMXPlayer::pyOMXPlayer = mod.attr("OMXPlayer")(_file, args, NULL, NULL, _dbus_name, _pause);
        
        pyOMXPlayer.attr("pauseEvent"   ) = py::make_function(&OMXPlayer::onPause);
        
        OMXPlayer::active = false;

    }
    catch(py::error_already_set){
        PyErr_Print();
    }

}


void OMXPlayer::onPause(){
    std::cout << "onPause" << std::endl;
}

void OMXPlayer::pause(){
    try{
        OMXPlayer::pyOMXPlayer.attr("pause")();
    }
    catch(py::error_already_set){
        PyErr_Print();
    }
}

OMXPlayer.h

#include <boost/python.hpp>
#include <boost/function.hpp>

#include <vector>
#include <iostream>
#include <atomic>

namespace py = boost::python;

class OMXPlayer{
    public:
        OMXPlayer(std::string _file, 
            std::vector<std::string> _args, 
            bool _pause = false, 
            std::string _dbus_name = "");
        
        void pause();
        void onPause();
};

main.cpp 函数:

#include "OMXPlayer.h"

int main(){
    
    OMXPlayer player1("/root/Setteventi.mp4", std::vector<std::string> {"--loop"}, false, "org.mpris.MediaPlayer2.omxplayer1");

    player1.pause();


}

你可以从这里看到python类:https://python-omxplayer-wrapper.readthedocs.io/en/latest/_modules/omxplayer/player/

当 python 端的 eventPause 被调用时,它会抛出这个:

Traceback (most recent call last):
  File "<decorator-gen-56>", line 2, in pause
  File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 48, in wrapped
    return fn(self, *args, **kwargs)
  File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 550, in pause
    self.pauseEvent(self)
Boost.Python.ArgumentError: Python argument types in
    None.None(OMXPlayer)
did not match C++ signature:
    None(OMXPlayer {lvalue})
Traceback (most recent call last):
  File "<decorator-gen-56>", line 2, in pause
  File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 48, in wrapped
    return fn(self, *args, **kwargs)
  File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 550, in pause
    self.pauseEvent(self)
Boost.Python.ArgumentError: Python argument types in
    None.None(OMXPlayer)
did not match C++ signature:
    None(OMXPlayer {lvalue})

【问题讨论】:

  • 来自boost docs: "如果 F 是一个指向成员函数的指针类型,函数调用的目标对象 (*this) 将从第一个 Python 参数中获取,随后Python 参数将用作 f 的参数。”那么,您是否尝试简单地传递&amp;OMXPLayer::onPause?结果是什么?显示完整的示例。
  • 是的,我已经尝试过你说的方法,但是它不起作用,因为函数签名不同,从我编辑的示例中可以看出。
  • 嗯,是的,因为 python 用 self 调用它,这是一个不同的 OMXPlayer 类。如果你 boost::bindstd::bind this 指针,错误是什么?
  • 我不能或者我不知道怎么做。如果我只是尝试:pyOMXPlayer.attr("pauseEvent" ) = py::make_function( boost::bind(&amp;OMXPlayer::onPause, this) ); 它不会编译错误:/usr/include/boost/python/make_function.hpp:104:57: error: no matching function for call to ‘get_signature(boost::_bi::bind_t&lt;void, boost::_mfi::mf0&lt;void, OMXPlayer&gt;, boost::_bi::list1&lt;boost::_bi::value&lt;OMXPlayer*&gt; &gt; &gt;&amp;)’ f,default_call_policies(), detail::get_signature(f)); make_function 需要一个函数并且 boost:bind 返回一个对象。
  • 应该或多或少:py::make_function(boost::bind(&amp;OMXPlayer::onPause, this)); 或者更确切地说是py::make_function(boost::bind(&amp;OMXPlayer::onPause, this, _1)); 和签名:void onPause(py::object player),因为 python 用一个参数调用它。或者使用标准库:py::make_function(std::bind(&amp;OMXPlayer::onPause, this, std::placeholders::_1)); 抱歉没有更准确,今天我没有任何好的环境来尝试你的代码。

标签: python c++ boost-python


【解决方案1】:

好的,在@pptaszni 的帮助下,我找到了方法。

问题在于 boost 无法解除函数签名,因为 boost::bind 返回一个函数对象。

为了避免这个问题,我必须在调用make_function时指定签名。

例子:

pyOMXPlayer.attr("pauseEvent") = py::make_function( boost::bind(&OMXPlayer::onPause, this, _1), py::default_call_policies(), boost::mpl::vector<void, py::object>() );

棘手的部分是py::make_function的最后一个参数

谢谢@pptaszni

【讨论】:

    猜你喜欢
    • 2011-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-25
    • 2013-04-09
    • 2011-10-06
    • 2021-08-05
    • 1970-01-01
    相关资源
    最近更新 更多