Я предоставляю API для Python, написанного на C ++, для которого у меня нет доступа к изменениям, используя Boost Python.
Я успешно представил методы, возвращающие ссылки на std: map, где ключ, значениепары являются типами значений - например:
class_< std::map<std::string, std::string> >("StringMap")
.def(map_indexing_suite< std::map<std::string, std::string>, true >());
Это работает без проблем.Но при попытке получить аналогичный результат, когда значения карты являются указателями на классы, которые я представил в 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, как и в случае базового метода, который возвращает необработанный указатель.
У меня вопрос, каков наилучший способ сделать это?
Из Googling мне кажется, что я могу указать DerivedPolicies
дочерний класс map_indexing_suite
, который будет перегружать необходимые части для переносаХ * в соответствующем return_value_policy
.Однако до сих пор мне не удалось собрать что-нибудь такое, на что компилятор не ругается!
Я также подозреваю, что могу буквально скопировать и вставить весь map_indexing_suite
и переименовать его, и сделатьизменения в нем дают новый indexing_suite
с правильным return_value_policy
, но это выглядит некрасиво по сравнению с решением, использующим DerviedPolicies
- при условии, что я прав, что DeriviedPolicies
можно использовать вообще!
Любая помощь, указатели или примеры с благодарностью получены!
РЕДАКТИРОВАТЬ
Я доказал, что опция вырезать и вставить работает с одним тривиальным изменением is_class
до is_pointer
.Любопытно, что is_pointer
не допускается в оригинале, так как целевая политика может обрабатывать указатели.Мне еще предстоит убедить себя, что это ограничение срока службы объекта, означающее, что указатели не допускаются в оригинале?
Весь класс является общедоступным, поэтому я подозреваю, что можно избежать полной вырезки и вставки, простонаследование от map_indexing_suite
или, возможно, с помощью загадочного параметра DerivedPolicies
?
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
Теперь смотрите ответ