ОК, так что это довольно сложный вопрос для ответа в целом.Основная причина вашей проблемы в том, что на самом деле нет типа python, который в точности эквивалентен указателю на функцию C.Функции Python довольно близки, но их интерфейс не совпадает по нескольким причинам.
Во-первых, я хочу упомянуть технику для переноса конструктора отсюда: http://wiki.python.org/moin/boost.python/HowTo#namedconstructors.2BAC8factories.28asPythoninitializers.29. Это позволяет вамнаписать функцию __init__
для вашего объекта, которая не соответствует непосредственно конструктору C ++.Также обратите внимание, что вам, возможно, придется указать boost::python::no_init
в конструкции boost::python::class_
, а затем def
настоящую __init__
функцию позже, если ваш объект не может быть создан по умолчанию.
Вернуться квопрос: есть ли небольшой набор функций, которые вы обычно хотите передать?В этом случае вы можете просто объявить специальный enum (или специализированный класс), сделать перегрузку вашего конструктора, который принимает enum, и использовать его для поиска реального указателя функции.Вы не можете напрямую вызывать функции из python, используя этот подход, но это не так уж плохо, и производительность будет такой же, как при использовании реальных указателей на функции.
Если вы хотите предоставить общий подход, который будетработать для любого вызываемого питона, все становится сложнее.Вам придется добавить конструктор к вашему объекту C ++, который принимает общий функтор, например, используя boost::function
или std::tr1::function
.Вы можете заменить существующий конструктор, если хотите, потому что указатели на функции будут правильно преобразовываться в этот тип.
Итак, предполагая, что вы добавили конструктор 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));
Я упустил подробности о том, как преобразовывать указатели в и из python - это, очевидно, то, что вам придется решить, потому что там возникают проблемы с временем жизни объекта.
Если вам нужно вызвать указатели функций, которые вы передадите этой функции из Python, то вам нужно def
этих функций, используя Boost.Python в какой-то момент.Этот второй подход будет хорошо работать с этими определенными функциями, но их вызов будет медленным, потому что объекты будут излишне преобразовываться в и из Python при каждом вызове.
Чтобы исправить это, вы можете изменитьCreateSomeClassFromPython
для распознавания известных или общих функциональных объектов и замены их действительными указателями функций.Вы можете сравнить идентичность объектов Python в C ++, используя object1.ptr() == object2.ptr()
, что эквивалентно id(object1) == id(object2)
в Python.
Наконец, вы, конечно, можете объединить общий подход с подходом enum.Имейте в виду, что при этом правила перегрузки boost :: python отличаются от правил C ++, и это может укусить вас при работе с такими функциями, как CreateSomeClassFromPython
.Boost.Python тестирует функции в порядке их определения, чтобы увидеть, можно ли преобразовать аргументы времени выполнения в типы аргументов C ++.Таким образом, CreateSomeClassFromPython
предотвратит использование конструкторов с одним аргументом def'd позже, чем он будет использоваться, потому что его аргумент соответствует любому объекту python.Обязательно ставьте его после других функций __init__
с одним аргументом.
Если вы обнаружите, что часто делаете подобные вещи, то вам, возможно, стоит взглянуть на общую технику boost :: functionна той же странице с именованным конструктором): http://wiki.python.org/moin/boost.python/HowTo?action=AttachFile&do=view&target=py_boost_function.hpp.