暴露C ++函数,使用Boost.Python返回指针 [英] Exposing C++ functions, that return pointer using Boost.Python

查看:1161
本文介绍了暴露C ++函数,使用Boost.Python返回指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用Boost.Python将以下C ++函数公开给Python:

  int * test1(){
return new int(42);
}

//现在使用Boost.Python显示函数

BOOST_PYTHON_MODULE(libtest1)
{
使用命名空间boost :: python ;
def(test1,test1);
}

当我试图编译这个库时,会发生错误)Boost.Python不知道,如何将int *转换为PyObject。



我认为需要做的是定义转换结构,像这样: / p>

 模板< class T> 
struct int_ptr_to_python
{
static PyObject * convert(int * i_ptr)
{
return i_ptr;
}
};

并传递给BOOST_PYTHON_MODULE声明:

  BOOST_PYTHON_MODULE(libtest1)
{
using namespace boost :: python;
def(test1,test1);
to_python_converter< int *,int_ptr_to_python< int *> >();
}

但它也不起作用。我不能找到任何有关如何处理函数的信息。



有人可以帮助吗?

int * 与Boost.Python,因为没有意义




  • 如果目标是向Python返回一个数字,那么返回 int 。这可能需要使用辅助函数来修改旧版API。

  • 如果目标是返回一个指向使用new-expression分配的对象的指针,那么该对象必须是类或联合






而是必须使用特定的政策比现在的最终解决方案立即,我想花时间来逐步通过编译器错误。使用Boost.Python,有时使用预C ++ 11静态断言来在编译器消息中提供指令。不幸的是,它可能有点难以找到它们之间的重模板。



以下代码:

  #include< boost / python.hpp> 

int * make_int(){return new int(42); }

BOOST_PYTHON_MODULE(example)
{
namespace python = boost :: python;
python :: def(make_int,& make_int);
}

在clang中生成以下相关输出,重要的细节以粗体显示:

 
... / boost / python / detail / caller.hpp:102:98:错误:
没有成员名为 get_pytype'in'boost :: python :: detail ::
define_a_return_value_policy_to_wrap_functions_returning< int *> '
... create_result_converter((PyObject *)0,(ResultConverter *) 0,
(ResultConverter *)0).g ...



Boost.Python通知我们 boost :: python :: return_value_policy 需要为返回 int * 的函数指定。有多种型号的 ResultConverterGenerators 。通常,策略用于控制返回对象的所有权或生存期语义。由于原始代码中的函数直接将新的指针返回到Python,因此 boost :: python :: manage_new_object 是适当的,如果调用者需要负责删除对象。



为对象管理指定策略仍然失败:

  #include< boost / python.hpp> 

int * make_int(){return new int(42); }

BOOST_PYTHON_MODULE(example)
{
namespace python = boost :: python;
python :: def(make_int,& make_int,
python :: return_value_policy< python :: manage_new_object>());
}

产生以下相关输出:

 
... / boost / python / object / make_instance.hpp:27:9:
错误:没有匹配函数调用'assertion_failed'
< b> BOOST_MPL_ASSERT((mpl :: or_ ,is_union< T>)));

在这种情况下,Boost.Python通知我们从一个函数返回的对象 managed_new_object ResultConverterGenerator必须是 union 。对于 int * ,最合适的解决方案是在通过Boost.Python层时返回 int 。但是,为了完整性,下面显示:




  • 使用辅助函数修改旧版API。

  • 如何使用返回指针的工厂函数限制用户定义类型的创建。



  #include< boost / python.hpp> 

///旧版API。
int * make_int(){return new int(42); }

///将旧API应用于Python的辅助函数。
int py_make_int()
{
std :: auto_ptr< int> ptr(make_int());
return * ptr;
}

///将旧API修改为Python的辅助类。
class holder
:private boost :: noncopyable
{
public:
holder()
:value_(make_int())
{ }

int get_value()const {return * value_; }
void set_value(int value){* value_ = value; }

private:
std :: auto_ptr< int>值_;
};

///持有者类的工厂函数。
holder * make_holder()
{
return new holder();
}

BOOST_PYTHON_MODULE(example)
{
namespace python = boost :: python;
python :: def(make_int,& py_make_int);

python :: class_< holder,boost :: noncopyable>(Holder,python :: no_init)
.add_property(value,
python :: make_function & holder :: get_value),
python :: make_function(& holder :: set_value))
;

python :: def(make_holder,& make_holder,
python :: return_value_policy< python :: manage_new_object>());
}

互动用法:



< pre class =lang-python prettyprint-override> >>> import example
>>> assert(42 == example.make_int())
>>> holder = example.Holder()
回溯(最近最后一次调用):
在< module>中第1行的文件< stdin&
RuntimeError:此类不能从Python实例化
>>> holder = example.make_holder()
>>>> assert(42 == holder.value)
>>> holder.value * = 2
>>>> assert(84 == holder.value)


I want to expose the following C++ function to Python using Boost.Python:

int* test1() {
    return new int(42);
}

// Now exposing the function with Boost.Python

BOOST_PYTHON_MODULE(libtest1)
{
    using namespace boost::python;
    def("test1", test1);
}

When I try to compile this library the error occurs due to (it's my guess) Boost.Python don't know, how to convert int* to PyObject.

I think what needs to be done is to define conversion structure, something like this:

template<class T>
struct int_ptr_to_python
{
   static PyObject* convert(int* i_ptr)
   {
        return i_ptr;
   }
};

And pass it to the BOOST_PYTHON_MODULE declaration:

BOOST_PYTHON_MODULE(libtest1)
{
    using namespace boost::python;
    def("test1", test1);
    to_python_converter<int*, int_ptr_to_python<int*> >();
}

But it also doesn't work. And I can't find any information about how the functions, that return pointers should be handled.

Does anyone can help?

解决方案

In short, one cannot directly expose a function returning int* with Boost.Python, as there is no meaningful corresponding type in Python given integers are immutable.

  • If the goal is to return a number to Python, then return int by value. This may require using an auxiliary function to adapt legacy APIs.
  • If the goal is to return a pointer to an object allocated with a new-expression, then the object must be a class or union, and the function must be exposed with specific policies to indicate ownership responsabilities.

Rather than present the final solution immediately, I would like to take the time to step through the compiler errors. With Boost.Python, sometimes pre-C++11 static assertions are used to provide instructions in the compiler messages. Unfortunately, it can be a bit difficult to find them amongst the heavy templates.

The following code:

#include <boost/python.hpp>

int* make_int() { return new int(42); }

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::def("make_int", &make_int);
}

produces the following relevant output in clang, with the important details accentuated in bold:

.../boost/python/detail/caller.hpp:102:98: error:
  no member named 'get_pytype' in 'boost::python::detail::
    specify_a_return_value_policy_to_wrap_functions_returning<int*>'
  ...create_result_converter((PyObject*)0, (ResultConverter *)0, 
                             (ResultConverter *)0).g...

Boost.Python is informing us that a boost::python::return_value_policy needs to be specified for functions returning int*. There are various models of ResultConverterGenerators. Often times the policies are used to control the ownership or lifetime semantics of the returned object. As the function in the original code is returning a new pointer directly to Python, the boost::python::manage_new_object is appropriate if the caller is expected to take responsibility for deleting the object.

Specifying a policy for object management still fails:

#include <boost/python.hpp>

int* make_int() { return new int(42); }

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::def("make_int", &make_int,
    python::return_value_policy<python::manage_new_object>());
}

produces the following relevant output:

.../boost/python/object/make_instance.hpp:27:9:
  error: no matching function for call to 'assertion_failed'
    BOOST_MPL_ASSERT((mpl::or_<is_class<T>, is_union<T> >));

In this case, Boost.Python is informing us that the object returned from a function with a managed_new_object ResultConverterGenerator must be either a class or union. For an int*, the most appropriate solution is to return the int by value when passing through the Boost.Python layer. However, for completeness, below demonstrates:

  • Using an auxiliary function to adapt a legacy API.
  • How to limit the creation of a user defined type with a factory function that returns pointers.

#include <boost/python.hpp>

/// Legacy API.
int* make_int() { return new int(42); }

/// Auxiliary function that adapts the legacy API to Python.
int py_make_int()
{
  std::auto_ptr<int> ptr(make_int());
  return *ptr;
}

/// Auxiliary class that adapts the legacy API to Python.
class holder
  : private boost::noncopyable
{
public:
  holder()
    : value_(make_int())
  {}

  int get_value() const     { return *value_; }
  void set_value(int value) { *value_ = value; }

private:
  std::auto_ptr<int> value_;
};

/// Factory function for the holder class.
holder* make_holder()
{
  return new holder();
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::def("make_int", &py_make_int);

  python::class_<holder, boost::noncopyable>("Holder", python::no_init)
    .add_property("value",
      python::make_function(&holder::get_value),
      python::make_function(&holder::set_value))
    ;

  python::def("make_holder", &make_holder,
    python::return_value_policy<python::manage_new_object>());
}

Interactive usage:

>>> import example
>>> assert(42 == example.make_int())
>>> holder = example.Holder()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: This class cannot be instantiated from Python
>>> holder = example.make_holder()
>>> assert(42 == holder.value)
>>> holder.value *= 2
>>> assert(84 == holder.value)

这篇关于暴露C ++函数,使用Boost.Python返回指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆