Cython:具有自定义参数类型的STD ::功能回调
Cython: std::function callbacks with custom parameter types
请在回答之前阅读此帖子:将封闭式从Cython传递到C
在接受的答案中,它整齐地展示了如何使用Boost Python将Python函数转换为std::function
。
按照此示例,我能够将std::function
作为参数的功能包裹起来,并使用Python函数将其称为输入。但是,这仅在std::function
参数为 int
, double
, string
等的原始内容时起作用。
关于如何为自定义类型制作这项工作的任何指南将受到高度赞赏。
这不是一个完整的答案 - 它假设您可以从我以前的答案中填补问题所基于的空白。不幸的是,它比这种情况要复杂一些。
只是为了定义问题 - 假设您有一个自定义C 类的参数,例如:
class cpp_class {
// some non-trivial contents
};
因此,您的C 接口看起来像这样:
void call_some_std_func(std::function<void(cpp_class&)> callback) {
callback(5,std::string("hello"));
}
要做的第一件事是为您的C 类编写一份Cython包装器(原则上,您可以改为Boost Python包装器)。在这里,您需要选择有关C 对象的"所有权"。首选是制作副本:
cdef extern from "cpp_file.hpp":
cppclass cpp_class:
pass # details
cdef class CyWrapper:
cdef cpp_class* ptr
def __dealloc__(self):
del self.ptr
# other details following standard wrapper pattern
cdef public make_CyWrapper(cpp_class& x):
obj = CyWrapper()
obj.ptr = new cpp_class(x)
return obj
我已经创建了一个具有破坏函数的包装程序类,该类别可以处理内存和可公开访问的构造函数,可以从外部代码调用。此版本是安全的,因为您的包装器拥有其拥有的对象,因此无法写入无效的内存。但是,由于它制作了副本,因此您无法更改原始C 对象。
第二个选项是将指针固定到您不拥有的对象。代码基本上是相同的,除了您删除__dealloc__
并避免在make_CyWrapper
中制作副本:
obj.ptr = &x // instead of new cpp_class(x)
这是不安全的 - 您需要确保您的C 对象要列出Cython包装器 - 但允许您修改对象。
您还可以想象其他一些选择:您可以使用Cython包装器将现有对象的所有权(这样的方案都必须通过指针而不是参考来传递,否则它可以使用移动构造函数);您可以将C 类解构为以基本类型表示的表示,并将其传递给Python。您可以使用共享的指针来分配所有权;或者,一旦持有C 实例,您就有更精细的方式将Cython包装商标记为"无效"。
您接下来要做的事情取决于您是使用boost python(因为它方便,可呼叫的python对象)还是制作自己的版本。(我在上一个答案中表现出了两种可能性)。
假设Boost Python,您需要做两件事 - 告诉它有关转换的信息,并确保它导入包装器所定义的模块(如果您不这样做,则会遇到令人兴奋的细分故障)
struct convert_to_PyWrapper {
static PyObject* convert(const cpp_class& rhs) {
// the const_cast here is a bit dodgy, but was needed to make it work
return make_CyWrapper(const_cast<cpp_class&>(rhs));
}
};
inline void setup_boost_python() {
PyInit_your_module_name(); // named inityour_module_name in Python 2
boost::python::to_python_converter<
cpp_class,
convert_to_PyWrapper>();
}
您需要在尝试使用回调之前确保您的Python/Cython代码调用" setup_boost_python"(如果将其放在模块级别上,则在导入上完成,这是理想的)。
>如果您正在遵循我的"手动"方案(避免对Boost Python的依赖性),则需要修改call_obj
Cython函数,该函数将C 用于Cython Type转换。
cdef public void call_obj(obj, cpp_class& c):
obj(make_CyWrapper(c))
您还需要在使用前确保将包装器Cython模块导入(否则您会得到分割故障)。我在" py_object_wrapper.hpp"中做到了这一点
void operator()(cpp_class& a) {
PyInit_your_module_name();
if (held) {
call_obj(held,a);
}
}
- 架构决策:返回std::future还是提供回调
- C++ 事件管理器的回调,使用 std::function 和 std:bind 以及派生类作为参数
- 从其存储的回调中删除 std::函数是否安全
- Boost.Asio:不能使用 std::bind() 来指定回调
- 安全回调提供程序(SFINAE,std::正向和过载解析)
- 为什么模板参数推导失败,std::函数回调的可变参数模板参数?
- std::包含 std::函数回调的多个包装器的向量不起作用
- 使用 void 函数作为回调,从 "std::function<void ()>?
- GUI滑块的动态数量,该数量更新具有回调中值的std ::向量
- 将回调函数中对对象的引用传递给 std::thread
- std::函数,带有 SDL 事件回调的 lambda 错误
- 带有 std::函数和参数的回调
- 用STD ::函数作为集体成员创建回调
- 如何使用std::bind向信使系统添加成员回调
- Cython:具有自定义参数类型的STD ::功能回调
- 自己的std ::带有回调或事件的ISTREAM,以避免拉或阻止读取
- C 11 std :: bind and auto的编译错误,用于回调函数参数
- 无法访问在 std 回调中传递的对象变量
- 使用std::函数进行回调
- std::list libev 回调崩溃