boost::python:如何调用需要指针的函数?

发布于 2024-09-26 15:43:35 字数 491 浏览 2 评论 0原文

我有一个函数,它接受一个 int 指针并通过 boost::python 公开它。我怎样才能从Python调用这个函数?

在 C++ 中使用 boost::python:

void foo(int* i);
...
def("foo", foo);

在 python:

import foo_ext
i = 12
foo_ext.foo(i)

结果中

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
foo(int)
did not match C++ signature:
foo(int* i)

那么如何传递指针呢?

I have a function that takes an int-pointer and exposed it via boost::python. How can I call this function from python?

in C++ with boost::python:

void foo(int* i);
...
def("foo", foo);

in python:

import foo_ext
i = 12
foo_ext.foo(i)

results in

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
foo(int)
did not match C++ signature:
foo(int* i)

So how to pass a pointer?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

谈下烟灰 2024-10-03 15:43:35

简短的回答是:你不能。 Python 没有指针

长答案是:根据用例有各种各样的解决方法。

我注意到您在示例中使用了 int 和 int* 。 Int(以及 float、str 和 bool)是一种特殊情况,因为它在 Python 中是不可变的。

假设您传入的对象实际上并不是 int。

有一个包装函数,它将参数作为引用,获取地址并将其传递给实际函数。这将在 python 中无缝运行。


好吧,所以说它确实是一个 int。现在你有问题了。您无法更改传入的 int。如果您尝试相同的解决方案,boost::python 将在运行时抱怨左值。还有几种选择。

假设您不需要在函数退出后查看 int 的样子,并且您知道该函数不会在函数返回后将指针隐藏起来以取消引用:

您的包装器现在应该按值或 const 引用获取 int 。其他一切都一样。


也许您只需要查看之后的状态(int 是一个 OUT 边界):

您的包装函数现在将不带参数,并将本地 int 的地址传递给实际函数。它将返回该值。如果您的函数已经有返回值,它现在应该返回一个元组。


输入和输出都很重要,并且您知道该函数不会在函数返回后隐藏指针以取消引用:

将上面的两者结合起来。包装器按值获取一个 int 并返回另一个不同的 int。


该函数期望在函数返回后将指针隐藏起来以取消引用:

没有真正好的解决方案。您可以在 C++ 中创建并公开包含 C++ int 的对象。包装器将通过引用获取该对象,提取所包含的 int 的地址并将其传递给实际函数。让对象在Python中保持活动状态(并且不受垃圾收集器的影响)直到库完成它现在是Python编写者的问题,如果他犯了错误,数据就会损坏或者解释器崩溃。

Short answer is: You can't. Python does not have pointers

Long answer is: There are assorted workarounds depending on use-case.

I notice that you are using an int and an int* in your example. Int (along with float, str, and bool) is a special case because it is immutable in python.

Lets say that the object that you are passing in is not really an int.

Have a wrapper function that takes the argument as a reference, takes the address and passes it on to the actual function. This will work seamlessly in python.


Ok, so say it really was an int. Now you have a problem. You can not change the int you passed in. If you try the same solution, boost::python will complain about l-values at runtime. There are still several options.

Let's say that you do not need to see what the int looks like after the function exits and you know that the function will not squirrel away the pointer to dereference after the function returns:

Your wrapper should now take the int by value or by const reference. Everything else is the same.


Maybe you ONLY need to see the after state (the int is an OUT perimeter):

Your wrapper function will now take no arguments, and will pass the address of a local int to the actual function. It will return that value. If you function already has a return value it should now return a tuple.


Both the input and the output are important and you know that the function will not squirrel away the pointer to dereference after the function returns:

Combine the two above. The wrapper takes one int by value and returns a different int.


The function expects to squirrel away the pointer to dereference after the function returns:

There is no real good solution. You can create and expose an object in c++ that contains a c++ int. The wrapper will take that object by reference, extract the address of the contained int and pass it on to the actual function. Keeping the object alive in python (and safe from the garbage collector) until the library is done with it is now the python writer's problem, and if he goofs the data is corrupt or the interpretor crashes.

动次打次papapa 2024-10-03 15:43:35

来自 python.org 的 boost.python HowTo

也许您想要结果
包含原始指针的 Python 对象
到论点?在这种情况下,
需要注意的是,如果
C++ 对象先于
Python 对象,该指针将
悬挂并使用Python对象可能
导致崩溃。

以下是公开可变 C++ 的方法
模块初始化期间的对象:

scope().attr("a") = object(ptr(&class_instance));

From python.org's boost.python HowTo

Perhaps you'd like the resulting
Python object to contain a raw pointer
to the argument? In that case, the
caveat is that if the lifetime of the
C++ object ends before that of the
Python object, that pointer will
dangle and using the Python object may
cause a crash.

Here's how to expose mutable C++
object during module initialisation:

scope().attr("a") = object(ptr(&class_instance));
∝单色的世界 2024-10-03 15:43:35

在大多数情况下,您可以避免将原始指针传递给函数,但是当确实需要时,您可以使用适配器将 C++ 指针的 Python 对象创建为指向原始对象,如下所示:

template<typename PtrT>
struct PtrAdapter {
    auto& get(PtrT ptr)  { return *ptr; }
};

然后定义指针的映射类型到 Python 对象并允许隐式转换:

class_<Cluster<LinksT>*, noncopyable>(typpedName<LinksT>("ClusterPtr", true, true)
, "Raw hierarchy cluster pointer\n")
    .def("__call__", &PtrAdapter<Cluster<LinksT>*>::get,
        return_internal_reference<>(),
        "referenced cluster")
    ;
register_ptr_to_python<Cluster<LinksT>*>();

请注意,原始对象类型也应该映射到 Python 对象(在本例中为 Cluster)。

那么对于这样的C++代码:

Cluster<LinksT>* cl = clusters.head();
process(cl);
Id cid = cl->id();

您可以使用类似的Python代码:

cl = clusters.head()
process(cl)
cid = cl.id()

In most cases you can avoid raw pointer passing to the function, but when it's really required you can make Python object for the C++ pointer to the original object using adapter in such way:

template<typename PtrT>
struct PtrAdapter {
    auto& get(PtrT ptr)  { return *ptr; }
};

then define mapping of the pointer type to Python object and allow implicit conversion:

class_<Cluster<LinksT>*, noncopyable>(typpedName<LinksT>("ClusterPtr", true, true)
, "Raw hierarchy cluster pointer\n")
    .def("__call__", &PtrAdapter<Cluster<LinksT>*>::get,
        return_internal_reference<>(),
        "referenced cluster")
    ;
register_ptr_to_python<Cluster<LinksT>*>();

Note that original object type also should have mapping to the Python object (in this case Cluster<LinksT>).

Then for such C++ code:

Cluster<LinksT>* cl = clusters.head();
process(cl);
Id cid = cl->id();

You can use similar Python code:

cl = clusters.head()
process(cl)
cid = cl.id()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文