boost :: python: как вызвать функцию, которая ожидает указатель? - PullRequest
6 голосов
/ 07 октября 2010

У меня есть функция, которая берет int-указатель и выставляет его через boost :: python. Как я могу вызвать эту функцию из Python?

в C ++ с boost :: python:

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

в питоне:

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)

Так как передать указатель?

Ответы [ 3 ]

4 голосов
/ 09 ноября 2010

Краткий ответ: : Вы не можете. Python не имеет указателей

Длинный ответ: В зависимости от варианта использования существуют различные обходные пути.

Я заметил, что вы используете int и int * в вашем примере. Int (наряду с float, str и bool) является особым случаем, потому что он неизменен в python.

Допустим, объект, который вы передаете, на самом деле не является целым.

Иметь функцию-обертку, которая принимает аргумент в качестве ссылки, получает адрес и передает его фактической функции. Это будет работать без проблем в Python.


Хорошо, так сказать, это действительно был int. Теперь у вас есть проблема. Вы не можете изменить переданный вами int. Если вы попробуете то же самое решение, boost :: python будет жаловаться на l-значения во время выполнения. Есть еще несколько вариантов.

Допустим, вам не нужно видеть, как выглядит int после выхода из функции, и вы знаете, что функция не будет сжимать указатель на разыменование после возврата из функции:

Ваша оболочка теперь должна принимать int по значению или по константной ссылке. Все остальное тоже самое.


Может быть, вам ТОЛЬКО нужно увидеть состояние после (int является периметром OUT):

Ваша функция-обертка теперь не будет принимать аргументов и будет передавать адрес локального int действительной функции. Это вернет это значение. Если ваша функция уже имеет возвращаемое значение, она теперь должна вернуть кортеж.


Важны как вход, так и выход, и вы знаете, что функция не будет сжимать указатель на разыменование после того, как функция вернет:

Объедините два выше. Оболочка принимает одно значение типа int и возвращает другое значение типа int.


Функция ожидает сжимать указатель на разыменование после возврата из функции:

Нет действительно хорошего решения. Вы можете создавать и открывать объект в C ++, который содержит C ++ Int. Оболочка возьмет этот объект по ссылке, извлечет адрес содержимого int и передаст его фактической функции. Сохранение объекта живым в python (и защита от сборщика мусора) до тех пор, пока библиотека не закончит с ним, теперь является проблемой автора python, и если он работает, данные повреждены или происходит сбой интерпретатора.

1 голос
/ 15 января 2014

В в большинстве случаев вы можете избежать передачи необработанного указателя на функцию , но когда это действительно необходимо, вы можете создать объект Python для указателя C ++ на исходный объект, используя адаптер таким образом:

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<LinksT>).

Тогда для такого кода C ++:

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

Вы можете использовать аналогичный код Python:

cl = clusters.head()
process(cl)
cid = cl.id()
1 голос
/ 07 октября 2010

С Python.org's Boost.python HowTo

Возможно, вы хотели бы получить Объект Python, содержащий необработанный указатель к аргументу? В этом случае предостережение в том, что если время жизни C ++ объект заканчивается до того из Объект Python, этот указатель будет болтаться и использование объекта Python может вызвать аварию.

Вот как выставить изменчивый C ++ объект во время инициализации модуля:

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