boost-python 当 C++ 方法 returns std::map<string,X*>
boost-python when C++ method returns std::map<string,X*>
我正在向 Python 公开一个 API,它是用 C++ 编写的,我无法使用 Boost Python.
进行更改
我已经成功公开返回对 std:map 的引用的方法,其中键值对是值类型 - 例如:
class_< std::map<std::string, std::string> >("StringMap")
.def(map_indexing_suite< std::map<std::string, std::string>, true >());
这可以无缝运行。但是当试图获得类似的结果时,地图值是指向 classes 的指针,我在 API 中公开的是行不通的:
struct X_wrap : X, wrapper<X>
{
X_wrap(int i): X(i) {}
// virtual methods here, omitted for brevity - as unlikely to be the issue
}
BOOST_PYTHON_MODULE(my_py_extension)
{
class_< std::map<std::string, X*> >("XPtrMap")
.def(map_indexing_suite< std::map<std::string, X*> >());
class_<X_wrap, boost::noncopyable, bases<XBase> >("X", init<int>())
// other definitions omitted
}
g++ 7.3.0 中出现错误:
/usr/include/boost/python/detail/caller.hpp:100:98: error: ‘struct boost::python::detail::specify_a_return_value_policy_to_wrap_functions_returning<X*>’ has no member named ‘get_pytype’
我理解为什么编译器会抱怨 - 映射中的 X*
需要包含在调用策略中,以便它可以返回到 Python,就像使用基本方法一样returns 原始指针。
我的问题是最好的方法是什么?
通过谷歌搜索,我发现我或许可以指定 map_indexing_suite
的 DerivedPolicies
子 class,这将使必要的部分超载以将 X* 包装在适当的 return_value_policy
.但是到目前为止,我还没有成功地把编译器不喜欢的任何东西放在一起!
我还怀疑我可以直接复制粘贴整个 map_indexing_suite
并重命名,并在其中进行更改以生成具有正确 return_value_policy
的新 indexing_suite
,但是与使用 DerviedPolicies
的解决方案相比,这似乎很难看 - 假设我是对的 DeriviedPolicies
完全可以使用!
非常感谢收到任何帮助、指示或示例!
编辑
我已经证明剪切和粘贴选项可以通过 is_class
到 is_pointer
的一个简单更改来工作。奇怪的是 is_pointer
在原始文件中是不允许的,因为目标策略可以处理指针。我还没有说服自己这是一个对象生命周期限制,这意味着原来不允许使用指针?
整个 class 是 public 所以我怀疑可以通过简单地继承 map_indexing_suite
或者使用神秘的 [=19 来避免完全剪切和粘贴=] 参数?
extension_def(Class& cl)
{
// Wrap the map's element (value_type)
std::string elem_name = "mapptr_indexing_suite_";
object class_name(cl.attr("__name__"));
extract<std::string> class_name_extractor(class_name);
elem_name += class_name_extractor();
elem_name += "_entry";
typedef typename mpl::if_<
mpl::and_<is_pointer<data_type>, mpl::bool_<!NoProxy> >
, return_internal_reference<>
, default_call_policies
>::type get_data_return_policy;
class_<value_type>(elem_name.c_str())
.def("__repr__", &DerivedPolicies::print_elem)
.def("data", &DerivedPolicies::get_data, get_data_return_policy())
.def("key", &DerivedPolicies::get_key)
;
}
编辑 2
现在看答案
从剪切和粘贴中稍微更简洁的实现是继承 map_indexing_suite - 需要进行一些调整才能使其正常工作。
这似乎相当明智 - 如果有人提出更简洁的解决方案或可以更好地解释 DerivedPolicies
那么太好了,否则我将在几天左右的时间内接受下面的答案...
using namespace boost;
using namespace boost::python;
//Forward declaration
template <class Container, bool NoProxy, class DerivedPolicies>
class mapptr_indexing_suite;
template <class Container, bool NoProxy>
class final_mapptr_derived_policies
: public mapptr_indexing_suite<Container,
NoProxy, final_mapptr_derived_policies<Container, NoProxy> > {};
template <
class Container,
bool NoProxy = false,
class DerivedPolicies
= final_mapptr_derived_policies<Container, NoProxy> >
class mapptr_indexing_suite
: public map_indexing_suite<
Container,
NoProxy,
DerivedPolicies
>
{
public:
// Must be explicit if the compiler is
// going to take from the base class
using typename map_indexing_suite<
Container,NoProxy,DerivedPolicies>::data_type;
using typename map_indexing_suite<
Container,NoProxy,DerivedPolicies>::value_type;
// Only one class needs to be overridden from the base
template <class Class>
static void
extension_def(Class& cl)
{
// Wrap the map's element (value_type)
std::string elem_name = "mapptr_indexing_suite_";
object class_name(cl.attr("__name__"));
extract<std::string> class_name_extractor(class_name);
elem_name += class_name_extractor();
elem_name += "_entry";
// use of is_pointer here is the only
// difference to the base map_indexing_suite
typedef typename mpl::if_<
mpl::and_<std::is_pointer<data_type>, mpl::bool_<!NoProxy> >
, return_internal_reference<>
, default_call_policies
>::type get_data_return_policy;
class_<value_type>(elem_name.c_str())
.def("__repr__", &DerivedPolicies::print_elem)
.def("data", &DerivedPolicies::get_data, get_data_return_policy())
.def("key", &DerivedPolicies::get_key)
;
}
};
我正在向 Python 公开一个 API,它是用 C++ 编写的,我无法使用 Boost Python.
进行更改我已经成功公开返回对 std:map 的引用的方法,其中键值对是值类型 - 例如:
class_< std::map<std::string, std::string> >("StringMap")
.def(map_indexing_suite< std::map<std::string, std::string>, true >());
这可以无缝运行。但是当试图获得类似的结果时,地图值是指向 classes 的指针,我在 API 中公开的是行不通的:
struct X_wrap : X, wrapper<X>
{
X_wrap(int i): X(i) {}
// virtual methods here, omitted for brevity - as unlikely to be the issue
}
BOOST_PYTHON_MODULE(my_py_extension)
{
class_< std::map<std::string, X*> >("XPtrMap")
.def(map_indexing_suite< std::map<std::string, X*> >());
class_<X_wrap, boost::noncopyable, bases<XBase> >("X", init<int>())
// other definitions omitted
}
g++ 7.3.0 中出现错误:
/usr/include/boost/python/detail/caller.hpp:100:98: error: ‘struct boost::python::detail::specify_a_return_value_policy_to_wrap_functions_returning<X*>’ has no member named ‘get_pytype’
我理解为什么编译器会抱怨 - 映射中的 X*
需要包含在调用策略中,以便它可以返回到 Python,就像使用基本方法一样returns 原始指针。
我的问题是最好的方法是什么?
通过谷歌搜索,我发现我或许可以指定 map_indexing_suite
的 DerivedPolicies
子 class,这将使必要的部分超载以将 X* 包装在适当的 return_value_policy
.但是到目前为止,我还没有成功地把编译器不喜欢的任何东西放在一起!
我还怀疑我可以直接复制粘贴整个 map_indexing_suite
并重命名,并在其中进行更改以生成具有正确 return_value_policy
的新 indexing_suite
,但是与使用 DerviedPolicies
的解决方案相比,这似乎很难看 - 假设我是对的 DeriviedPolicies
完全可以使用!
非常感谢收到任何帮助、指示或示例!
编辑
我已经证明剪切和粘贴选项可以通过 is_class
到 is_pointer
的一个简单更改来工作。奇怪的是 is_pointer
在原始文件中是不允许的,因为目标策略可以处理指针。我还没有说服自己这是一个对象生命周期限制,这意味着原来不允许使用指针?
整个 class 是 public 所以我怀疑可以通过简单地继承 map_indexing_suite
或者使用神秘的 [=19 来避免完全剪切和粘贴=] 参数?
extension_def(Class& cl)
{
// Wrap the map's element (value_type)
std::string elem_name = "mapptr_indexing_suite_";
object class_name(cl.attr("__name__"));
extract<std::string> class_name_extractor(class_name);
elem_name += class_name_extractor();
elem_name += "_entry";
typedef typename mpl::if_<
mpl::and_<is_pointer<data_type>, mpl::bool_<!NoProxy> >
, return_internal_reference<>
, default_call_policies
>::type get_data_return_policy;
class_<value_type>(elem_name.c_str())
.def("__repr__", &DerivedPolicies::print_elem)
.def("data", &DerivedPolicies::get_data, get_data_return_policy())
.def("key", &DerivedPolicies::get_key)
;
}
编辑 2
现在看答案
从剪切和粘贴中稍微更简洁的实现是继承 map_indexing_suite - 需要进行一些调整才能使其正常工作。
这似乎相当明智 - 如果有人提出更简洁的解决方案或可以更好地解释 DerivedPolicies
那么太好了,否则我将在几天左右的时间内接受下面的答案...
using namespace boost;
using namespace boost::python;
//Forward declaration
template <class Container, bool NoProxy, class DerivedPolicies>
class mapptr_indexing_suite;
template <class Container, bool NoProxy>
class final_mapptr_derived_policies
: public mapptr_indexing_suite<Container,
NoProxy, final_mapptr_derived_policies<Container, NoProxy> > {};
template <
class Container,
bool NoProxy = false,
class DerivedPolicies
= final_mapptr_derived_policies<Container, NoProxy> >
class mapptr_indexing_suite
: public map_indexing_suite<
Container,
NoProxy,
DerivedPolicies
>
{
public:
// Must be explicit if the compiler is
// going to take from the base class
using typename map_indexing_suite<
Container,NoProxy,DerivedPolicies>::data_type;
using typename map_indexing_suite<
Container,NoProxy,DerivedPolicies>::value_type;
// Only one class needs to be overridden from the base
template <class Class>
static void
extension_def(Class& cl)
{
// Wrap the map's element (value_type)
std::string elem_name = "mapptr_indexing_suite_";
object class_name(cl.attr("__name__"));
extract<std::string> class_name_extractor(class_name);
elem_name += class_name_extractor();
elem_name += "_entry";
// use of is_pointer here is the only
// difference to the base map_indexing_suite
typedef typename mpl::if_<
mpl::and_<std::is_pointer<data_type>, mpl::bool_<!NoProxy> >
, return_internal_reference<>
, default_call_policies
>::type get_data_return_policy;
class_<value_type>(elem_name.c_str())
.def("__repr__", &DerivedPolicies::print_elem)
.def("data", &DerivedPolicies::get_data, get_data_return_policy())
.def("key", &DerivedPolicies::get_key)
;
}
};