Python函数指针作为类构造函数参数 我有一个C++类,它需要在构造函数中函数指针(浮点(*MyFAULT)(vector *) > 我已经公开了一些Python函数指针。 使用此类的理想方法如下所示: import mymodule mymodule.some_class(mymodule.some_function)
我这样告诉Boost关于这门课:Python函数指针作为类构造函数参数 我有一个C++类,它需要在构造函数中函数指针(浮点(*MyFAULT)(vector *) > 我已经公开了一些Python函数指针。 使用此类的理想方法如下所示: import mymodule mymodule.some_class(mymodule.some_function),python,performance,compiler-errors,function-pointers,boost-python,Python,Performance,Compiler Errors,Function Pointers,Boost Python,我这样告诉Boost关于这门课: class_<SomeClass>("some_class", init<float(*)(vector<float>*)>); class_uu(“某些类”,init); 但我得到: error: no matching function for call to 'register_shared_ptr1(Sample (*)(std::vector<double, std::allocator<double
class_<SomeClass>("some_class", init<float(*)(vector<float>*)>);
class_uu(“某些类”,init);
但我得到:
error: no matching function for call to 'register_shared_ptr1(Sample (*)(std::vector<double, std::allocator<double> >*))'
错误:调用“register\u shared\u ptr1(Sample(*)(std::vector*)”时没有匹配的函数
当我试图编译它时
那么,有没有人对我如何在不失去从函数指针获得的灵活性的情况下修复错误有什么想法(即不返回到指示调用哪个函数的字符串)
也可以说,C++中编写此代码的要点是速度。因此,如果我仍然能够保持这种优势(函数指针在初始化过程中被分配给成员变量,并且在以后会被调用100多万次),那就太好了。
好的,所以这是一个很难回答的问题。问题的根本原因是,实际上没有与C函数指针完全等效的python类型。Python函数有点接近,但它们的接口不匹配有几个原因 首先,我想从这里提到包装构造函数的技术: . 这样,就可以为对象编写一个boost::python::class
构造中指定boost::python::no_init
,然后在以后指定def
一个真正的\uu init\uu
函数
回到问题上来:
是否只有一小部分函数通常需要传入?在这种情况下,您可以只声明一个特殊的枚举(或专用类),对接受该枚举的构造函数进行重载,并使用该重载查找实际的函数指针。您不能使用这种方法直接从python中调用函数,但也没有那么糟糕,而且性能将与使用真正的函数指针相同
如果您想提供一种适用于任何可调用python的通用方法,那么事情会变得更加复杂。您必须向C++对象添加一个构造函数,接受一个通用函子,例如使用<代码> Boo::函数< /> >或<代码> STD::Tr1::函数< />代码。如果需要,可以替换现有的构造函数,因为函数指针将正确转换为这种类型
因此,假设您已将boost::function
构造函数添加到SomeClass
,您应该将这些函数添加到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));
struct WrapPythonCallable
{
typedef float*结果类型;
显式WrapPythonCallable(const boost::python::object&wrapped)
:包装的(包装的)
{ }
浮点*运算符()(向量*参数)常量
{
//做任何你需要做的事情来转换成一个
//boost::python::objecthere
boost::python::object arg_as_python_object=/*…*/;
//用对象调用python-注意
//可使用运算符()重载调用,并返回
//一个boost::python::对象。
//此外,该调用还可以抛出boost::python::error\u ready\u set-
//你可能想在这里处理这个问题。
boost::python::object result\u object=wrapped\u(arg\u作为\u python\u object);
//执行从result_对象提取浮点*所需的任何操作,
//可能使用boost::python::extract
浮点*结果=/*…*/;
返回结果;
}
boost::python::对象包装;
};
//此函数是将添加到SomeClass的“构造函数包装器”。
//更改返回类型以匹配某个类的持有者类型,如
//使用共享ptr保持。
std::auto_ptr从Python创建SomeClassFromPython(
常量boost::python::object&可调用)
{
返回标准::自动检查(
新的SomeClass(WrapPythonCallable(callable));
}
//稍后,当告诉Boost.Python关于SomeClass时:
类(“某些类”,无初始)
.def(“uu init_uu”,make_构造函数(&CreateSomeClassFromPython));
我遗漏了关于如何在python中转换指针的细节——这显然是您必须解决的问题,因为存在对象生存期问题
如果需要调用将从Python传递到此函数的函数指针,则需要在某个时候使用Boost.Pythondef
这些函数。第二种方法可以很好地处理这些定义函数,但调用它们的速度会很慢,因为每次调用对象时都会不必要地将它们转换为Python或从Python转换过来
要解决这个问题,您可以修改CreateSomeClassFromPython
,以识别已知或常见的函数对象,并用它们真正的函数指针替换它们。您可以在C++中使用Python对象的身份比较< <代码> Objt1.pTr.= = Objt2.pTrr()/Cyto>,相当于python中的代码> id(Objt1)= ID(Objt2)/Cuth.<代码>
最后,您当然可以将常规方法与枚举方法相结合。在执行此操作时请注意,boost::python的重载规则与C++不同,在处理诸如CreateSomeClassFromPython
之类的函数时,这可能会影响您。Pothon测试函数按照它们被定义的顺序来查看运行时参数是否可以转换为C++参数类型。因此,CreateSomeClassFromPython
将阻止使用比它定义得晚的单参数构造函数,因为它的参数匹配任何python对象。请确保将其放在其他单参数\uuuu init\uuu
函数之后
如果您发现自己经常做这类事情,那么您可能想看看通用的boost::function包装技术(与命名的constru在同一页中提到)