Boost.Python函数指针作为类构造函数参数

2024-06-17 01:27:33 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个C++类,它需要构造函数中的函数指针(^ {< CD1>})
我已经向Python公开了一些函数指针。
使用此类的理想方法如下:

import mymodule
mymodule.some_class(mymodule.some_function)

所以我告诉Boost这门课是这样的:

^{pr2}$

但我得到:

error: no matching function for call to 'register_shared_ptr1(Sample (*)(std::vector<double, std::allocator<double> >*))'

当我试图编译它的时候。在

那么,有没有人知道如何在不损失函数指针所获得的灵活性的情况下修复错误(即不返回到指示调用哪个函数的字符串)?在

也可以说,C++中编写此代码的要点是速度。因此,如果我仍然能够保持这一优势(函数指针在初始化过程中被分配给成员变量,之后将被调用超过100万次)。在


Tags: 方法noimportfunctionerrorsomeclassmymodule
1条回答
网友
1楼 · 发布于 2024-06-17 01:27:33

好吧,这是一个很难回答的问题。问题的根本原因是没有一个python类型与C函数指针完全等价。Python函数有点接近,但是由于一些原因它们的接口不匹配。在

首先,我想从这里提到包装构造函数的技术: http://wiki.python.org/moin/boost.python/HowTo#namedconstructors.2BAC8factories.28asPythoninitializers.29。这样就可以为对象编写一个^ {< CD1> }函数,它不直接对应于实际的C++构造函数。另外请注意,如果对象不是默认可构造的,则可能必须在boost::python::class_构造中指定boost::python::no_init,然后def一个实__init__函数。在

回到问题上来: 你通常只想传递一小部分函数吗?在这种情况下,您只需声明一个特殊的枚举(或专用类),生成一个接受该枚举的构造函数的重载,然后使用该重载来查找实际的函数指针。使用这种方法,您不能直接从python调用函数,但也没那么糟糕,而且性能将与使用真正的函数指针相同。在

如果您想提供一种通用的方法,可以用于任何python调用,那么事情就变得更复杂了。您必须向C++对象添加一个构造函数,该类接受一般的函子,例如使用^ {CD6}}或^ {CD7}}。如果需要,可以替换现有的构造函数,因为函数指针将正确转换为此类型。在

因此,假设您已经向boost::function添加了一个boost::function构造函数,那么您应该将这些函数添加到python包装代码中:

struct WrapPythonCallable
{
    typedef float * result_type;
    explicit WrapPythonCallable(const boost::python::object & wrapped) 
        : wrapped_(wrapped)
    { }
    float * operator()(vector<float>* arg) const
    {
        //Do whatever you need to do to convert into a 
        //boost::python::object here
        boost::python::object arg_as_python_object = /* ... */;

        //Call out to python with the object - note that wrapped_ 
        //is callable using an operator() overload, and returns 
        //a boost::python::object.
        //Also, the call can throw boost::python::error_already_set - 
        //you might want to handle that here.
        boost::python::object result_object = wrapped_(arg_as_python_object);

        //Do whatever you need to do to extract a float * from result_object,
        //maybe using boost::python::extract
        float * result = /* ... */;
        return result;
    }
    boost::python::object wrapped_;
};

//This function is the "constructor wrapper" that you'll add to SomeClass.
//Change the return type to match the holder type for SomeClass, like if it's
//held using a shared_ptr.
std::auto_ptr<SomeClass> CreateSomeClassFromPython(
    const boost::python::object & callable)
{
    return std::auto_ptr<SomeClass>(
        new SomeClass(WrapPythonCallable(callable)));
}


//Later, when telling Boost.Python about SomeClass:
class_<SomeClass>("some_class", no_init)
    .def("__init__", make_constructor(&CreateSomeClassFromPython));

我忽略了关于如何在python和python之间转换指针的细节,这显然是您必须解决的问题,因为存在对象生存期问题。在

如果您需要调用从Python传递给这个函数的函数指针,那么您需要使用def这些函数Boost.Python在某个时候。第二种方法可以很好地处理这些def'd函数,但是调用它们的速度会很慢,因为每次调用对象时,对象都会不必要地在Python和Python之间进行转换。在

要解决这个问题,您可以修改CreateSomeClassFromPython来识别已知或常见的函数对象,并用它们的实际函数指针替换它们。您可以在Python中使用C++中的python对象的身份比较,使用^ {CD12}},相当于^ {CD13}}。在

最后,您当然可以将通用方法与enum方法结合起来。在做这一点时,要意识到:Python的重载规则不同于C++,在处理诸如^ {CD11}}之类的函数时,这可能会对你产生影响。Boost.Python测试的功能是按照它们的顺序来查看运行时参数是否可以转换为C++参数类型。因此,CreateSomeClassFromPython将阻止使用晚于它的单参数构造函数def'd,因为它的参数与任何python对象匹配。一定要把它放在其他单参数__init__函数之后。在

如果您发现自己经常做这类事情,那么您可能需要看看一般的boost::函数包装技术(在同一页提到的命名构造函数技术):http://wiki.python.org/moin/boost.python/HowTo?action=AttachFile&do=view&target=py_boost_function.hpp。在

相关问题 更多 >