【发布时间】:2025-12-13 05:30:01
【问题描述】:
我开始学习使用 boost python 并且有一个菜鸟问题。
我想编写一个函数,可以将其参数的生命周期与其结果联系起来,这样当我调用r = func(a) 时,如果我仍然有r 的引用,则参数a 将永远不会被销毁.文档建议对此类请求使用return_internal_reference 呼叫策略。但这是否要求r 是a 的内部引用,正如其名称所暗示的那样?
在下面的(过度简化的)示例中,假设我想将输入数组 a 的生命周期与生成的 lambda 函数联系起来,该函数不是输入 a 的内部引用。
#include <functional>
#include <boost/python.hpp>
#include <boost/python/return_internal_reference.hpp>
using namespace std;
using namespace boost::python;
function<float(int)> func(const float* a) {
return [=](int n) { return a[n]; };
}
BOOST_PYTHON_MODULE(test) {
def("func", func, return_internal_reference<1>());
}
我希望能够在python中做到以下几点:
f = func(a) # 'a' can be a temporary variable, say returned by another function
f(5) # but 'a' should not be destroyed at this step,
# because its lifetime is tied to 'f'
当我尝试编译上面的代码时,我遇到了下面列出的错误墙,但如果我删除return_internal_reference<1>() 调用策略,代码编译成功。
我很确定我错误地使用了这个呼叫策略,但不知道如何使它正确。任何指针将不胜感激。非常感谢!
$ g++ -std=c++11 -shared Test.cc -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -L/opt/local/lib -lboost_python-mt -lpython2.7 -o test.so
In file included from /opt/local/include/boost/preprocessor/iteration/detail/iter/forward1.hpp:52:0,
from /opt/local/include/boost/python/detail/invoke.hpp:63,
from /opt/local/include/boost/python/detail/caller.hpp:16,
from /opt/local/include/boost/python/object/function_handle.hpp:8,
from /opt/local/include/boost/python/converter/arg_to_python.hpp:19,
from /opt/local/include/boost/python/call.hpp:15,
from /opt/local/include/boost/python/object_core.hpp:14,
from /opt/local/include/boost/python/args.hpp:25,
from /opt/local/include/boost/python.hpp:11,
from Test.cc:2:
/opt/local/include/boost/python/detail/invoke.hpp: In instantiation of 'PyObject* boost::python::detail::invoke(boost::python::detail::invoke_tag_<false, false>, const RC&, F&, AC0&) [with RC = boost::python::detail::reference_existing_object_requires_a_pointer_or_reference_return_type<std::function<float(int)> >; F = std::function<float(int)> (*)(const float*); AC0 = boost::python::arg_from_python<const float*>; PyObject = _object]':
/opt/local/include/boost/python/detail/caller.hpp:223:13: required from 'PyObject* boost::python::detail::caller_arity<1u>::impl<F, Policies, Sig>::operator()(PyObject*, PyObject*) [with F = std::function<float(int)> (*)(const float*); Policies = boost::python::return_internal_reference<>; Sig = boost::mpl::vector2<std::function<float(int)>, const float*>; PyObject = _object]'
/opt/local/include/boost/python/object/py_function.hpp:38:33: required from 'PyObject* boost::python::objects::caller_py_function_impl<Caller>::operator()(PyObject*, PyObject*) [with Caller = boost::python::detail::caller<std::function<float(int)> (*)(const float*), boost::python::return_internal_reference<>, boost::mpl::vector2<std::function<float(int)>, const float*> >; PyObject = _object]'
Test.cc:14:1: required from here
/opt/local/include/boost/python/detail/invoke.hpp:75:82: error: no match for call to '(const boost::python::detail::reference_existing_object_requires_a_pointer_or_reference_return_type<std::function<float(int)> >) (std::function<float(int)>)'
return rc(f( BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, ac, () BOOST_PP_INTERCEPT) ));
^
In file included from /opt/local/include/boost/python/object/function_handle.hpp:8:0,
from /opt/local/include/boost/python/converter/arg_to_python.hpp:19,
from /opt/local/include/boost/python/call.hpp:15,
from /opt/local/include/boost/python/object_core.hpp:14,
from /opt/local/include/boost/python/args.hpp:25,
from /opt/local/include/boost/python.hpp:11,
from Test.cc:2:
/opt/local/include/boost/python/detail/caller.hpp: In instantiation of 'static const PyTypeObject* boost::python::detail::converter_target_type<ResultConverter>::get_pytype() [with ResultConverter = boost::python::detail::reference_existing_object_requires_a_pointer_or_reference_return_type<std::function<float(int)> >; PyTypeObject = _typeobject]':
/opt/local/include/boost/python/detail/caller.hpp:240:19: required from 'static boost::python::detail::py_func_sig_info boost::python::detail::caller_arity<1u>::impl<F, Policies, Sig>::signature() [with F = std::function<float(int)> (*)(const float*); Policies = boost::python::return_internal_reference<>; Sig = boost::mpl::vector2<std::function<float(int)>, const float*>]'
/opt/local/include/boost/python/object/py_function.hpp:48:35: required from 'boost::python::detail::py_func_sig_info boost::python::objects::caller_py_function_impl<Caller>::signature() const [with Caller = boost::python::detail::caller<std::function<float(int)> (*)(const float*), boost::python::return_internal_reference<>, boost::mpl::vector2<std::function<float(int)>, const float*> >]'
Test.cc:14:1: required from here
/opt/local/include/boost/python/detail/caller.hpp:102:109: error: 'struct boost::python::detail::reference_existing_object_requires_a_pointer_or_reference_return_type<std::function<float(int)> >' has no member named 'get_pytype'
return create_result_converter((PyObject*)0, (ResultConverter *)0, (ResultConverter *)0).get_pytype();
^
【问题讨论】:
标签: python c++ c++11 boost boost-python