avl*_*vli 11 c++ python boost boost-python
我想使用Boost.Python将以下C++函数公开给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);
}
Run Code Online (Sandbox Code Playgroud)
当我尝试编译这个库时,由于(我的猜测)Boost.Python不知道如何将int*转换为PyObject而发生错误.
我认为需要做的是定义转换结构,如下所示:
template<class T>
struct int_ptr_to_python
{
static PyObject* convert(int* i_ptr)
{
return i_ptr;
}
};
Run Code Online (Sandbox Code Playgroud)
并将其传递给BOOST_PYTHON_MODULE声明:
BOOST_PYTHON_MODULE(libtest1)
{
using namespace boost::python;
def("test1", test1);
to_python_converter<int*, int_ptr_to_python<int*> >();
}
Run Code Online (Sandbox Code Playgroud)
但它也行不通.而且我找不到有关如何处理返回指针的函数的任何信息.
有人可以帮忙吗?
Tan*_*ury 16
简而言之,不能直接公开int*使用Boost.Python 返回的函数,因为在Python中没有有意义的相应类型,因为整数是不可变的.
int值返回.这可能需要使用辅助功能来适应传统API.我不想立即提出最终解决方案,而是花时间逐步解决编译器错误.使用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);
}
Run Code Online (Sandbox Code Playgroud)
在clang中产生以下相关输出,重要细节以粗体突出显示:
.../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告诉我们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>());
}
Run Code Online (Sandbox Code Playgroud)
产生以下相关输出:
.../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> >));
在这种情况下,Boost.Python通知我们从具有managed_new_objectResultConverterGenerator 的函数返回的对象必须是class或union.对于a int*,最合适的解决方案是int在通过Boost.Python层时返回by值.但是,为了完整性,以下说明:
#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>());
}
Run Code Online (Sandbox Code Playgroud)
互动用法:
>>> 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)
Run Code Online (Sandbox Code Playgroud)