python - boost-python 当 C++ 方法返回 std::map<string,X*>

标签 python c++ boost boost-python

我正在向 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 >());

这可以无缝运行。但是当试图获得类似的结果时,其中映射值是指向我在 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,就像返回 a 的基本方法一样原始指针。

我的问题是最好的方法是什么?

从谷歌搜索中我发现我或许可以指定 map_indexing_suiteDerivedPolicies 子类,它将重载必要的部分以将 X* 包装在适当的 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

现在看答案

最佳答案

从剪切和粘贴中稍微更清晰的实现是继承 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 - boost-python 当 C++ 方法返回 std::map<string,X*>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55376475/

相关文章:

python - 没有名为 'websocket' 的模块

Python ASCII 和 Unicode 解码错误

c++ - 对父类(super class)的引用

c++ - Boost.Spirit 重叠 Action /重用终端 token

python - 通过 Babel 国际化 Python 2.6 应用程序

python - 如何找到与 python 中的值相关的键的数量?

C++语法问题

c++ - 有没有办法在 C++/Linux 中重用套接字地址

c++ - 如果可以加入,如何加入线程,否则什么都不做?

c++ - Boost::Asio,SSL 连接问题