Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python,将元组转换为Python works,vector<;元组>;不_Python_C++_Boost_Tuples_Boost Python - Fatal编程技术网

Python,将元组转换为Python works,vector<;元组>;不

Python,将元组转换为Python works,vector<;元组>;不,python,c++,boost,tuples,boost-python,Python,C++,Boost,Tuples,Boost Python,我已经使用Boost::Python一段时间了,结果一切正常。然而,昨天我试图找出,当我试图从Python访问某个特定类型(元组)时,为什么我认为我已经注册了该类型(元组)会给我带来错误 事实证明,虽然元组实际上是注册的,但当试图通过vector\u index\u套件包装的std::vector访问元组时,这已经不够了 我在想,为什么它不起作用?有什么办法可以让这一切顺利进行吗?我应该试着用手把向量包起来吗 以下是我的MVE: #include <tuple> #include &

我已经使用Boost::Python一段时间了,结果一切正常。然而,昨天我试图找出,当我试图从Python访问某个特定类型(元组)时,为什么我认为我已经注册了该类型(元组)会给我带来错误

事实证明,虽然元组实际上是注册的,但当试图通过
vector\u index\u套件
包装的
std::vector
访问元组时,这已经不够了

我在想,为什么它不起作用?有什么办法可以让这一切顺利进行吗?我应该试着用手把向量包起来吗

以下是我的MVE:

#include <tuple>
#include <vector>

#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>

template <typename T>
struct TupleToPython {
    TupleToPython() {
        boost::python::to_python_converter<T, TupleToPython<T>>();
    }

    template<int...>
    struct sequence {};

    template<int N, int... S>
    struct generator : generator<N-1, N-1, S...> { };

    template<int... S>
    struct generator<0, S...> {
        using type = sequence<S...>;
    };

    template <int... I>
    static boost::python::tuple boostConvertImpl(const T& t, sequence<I...>) {
        return boost::python::make_tuple(std::get<I>(t)...);
    }

    template <typename... Args>
    static boost::python::tuple boostConvert(const std::tuple<Args...> & t) {
        return boostConvertImpl(t, typename generator<sizeof...(Args)>::type());
    }

    static PyObject* convert(const T& t) {
        return boost::python::incref(boostConvert(t).ptr());
    }
};

using MyTuple = std::tuple<int>;
using Tuples = std::vector<MyTuple>;

MyTuple makeMyTuple() {
    return MyTuple();
}

Tuples makeTuples() {
    return Tuples{MyTuple()};
}

BOOST_PYTHON_MODULE(h)
{
    using namespace boost::python;

    TupleToPython<MyTuple>();
    def("makeMyTuple", makeMyTuple);

    class_<std::vector<MyTuple>>{"Tuples"}
        .def(vector_indexing_suite<std::vector<MyTuple>>());
    def("makeTuples", makeTuples);
}
编辑:
我已经意识到,如果
vector\u indexing\u suite
NoProxy
参数一起使用,则不会发生错误。但是,如果没有必要,我更愿意这样做,因为这会使导出的类在Python中变得不直观。

TupleToPython
注册C++-to-Python转换器和Python-to-C++转换器。这很好

另一方面,您希望通过引用返回向量元素。但是Python方面没有任何东西可以作为对元组的引用。转换为Python元组可以保持相同的值,但它完全脱离了原始C++元组。

看起来,为了通过引用导出元组,需要为它创建一个索引套件,而不是从Python转换器到/从Python转换器。我从来没有这样做过,也不能保证它会起作用

下面介绍如何将元组公开为类似Python对象的最小元组(仅使用len()和索引)。首先定义一些辅助函数:

template <typename A>
int tuple_length(const A&)
{
    return std::tuple_size<A>::value;
}

template <int cidx, typename ... A>
typename std::enable_if<cidx >= sizeof...(A), boost::python::object>::type
get_tuple_item_(const std::tuple<A...>& a, int idx, void* = nullptr)
{
    throw std::out_of_range{"Ur outta range buddy"};
}

template <int cidx, typename ... A, typename = std::enable_if<(cidx < sizeof ...(A))>>
typename std::enable_if<cidx < sizeof...(A), boost::python::object>::type
get_tuple_item_(const std::tuple<A...>& a, int idx, int = 42)
{
    if (idx == cidx)
        return boost::python::object{std::get<cidx>(a)};
    else
        return get_tuple_item_<cidx+1>(a, idx);
};

template <typename A>
boost::python::object get_tuple_item(const A& a, int index)
{
    return get_tuple_item_<0>(a, index);
}
模板
整数元组长度(常数A&)
{
返回std::tuple_size::value;
}
模板
typename std::enable_if=sizeof…(A),boost::python::object>::type
获取(常量std::tuple&a,int-idx,void*=nullptr)
{
抛出std::超出范围{“超出范围的伙伴”};
}
模板
typename std::enable_if::type
获取元组项(const std::tuple&a,int idx,int=42)
{
if(idx==cidx)
返回boost::python::object{std::get(a)};
其他的
返回get\u tuple\u item(a,idx);
};
模板
boost::python::object get\u tuple\u项(const A&A,int index)
{
返回get\u tuple\u item(a,索引);
}
然后公开特定元组:

using T1 = std::tuple<int, double, std::string>;
using T2 = std::tuple<std::string, int>;

BOOST_PYTHON_MODULE(z)
{
    using namespace boost::python;

    class_<T1>("T1", init<int, double, std::string>())
      .def("__len__", &tuple_length<T1>)
      .def("__getitem__", &get_tuple_item<T1>);

    class_<T2>("T2", init<std::string, int>())
      .def("__len__", &tuple_length<T2>)
      .def("__getitem__", &get_tuple_item<T2>);
}
使用T1=std::tuple;
使用T2=std::tuple;
BOOST_PYTHON_模块(z)
{
使用名称空间boost::python;
类(“T1”,init())
.def(“\uuuu len\uuuuu”,&tuple\u长度)
.def(“\uuuu getitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;
类(“T2”,init())
.def(“\uuuu len\uuuuu”,&tuple\u长度)
.def(“\uuuu getitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;
}

注意,这些准元组不同于真正的Python元组,它们是可变的(通过C++)。由于元组不变性,通过转换器和
NoProxy
导出看起来是一种可行的替代方法。

不应该
Tuples-makeTuples(){return Tuples{MyTuple()};}
be
Tuples-makeTuples(){return Tuples();}
而是@fedepad我这样做是为了让你可以调用
makeTuples()[0]
而不触发
越界
错误,因为向量将为空,您将看不到元组错误。不过,Boost已经通过引用处理任意类。为什么元组有什么不同?当然,如果导出类,元组会有不同。请注意,您必须使用
类{“Tuples”}
导出向量。因此,基本上,转换函数仅在需要按值传递某些内容时才有用,对吗?我们必须创建一个采用元组类型的模板类,并使用与本机Python元组相同的接口注册一个
,然后它才能工作。对吗?是的,这似乎是对的。我不太确定如何为std::tuple正确注册
\uuu len\uuuu
\uuuu getitem\uuuuu
,但如果你能管理好这一点,这看起来是正确的方法。@Svalorzen我用一些工作代码更新了答案。
using T1 = std::tuple<int, double, std::string>;
using T2 = std::tuple<std::string, int>;

BOOST_PYTHON_MODULE(z)
{
    using namespace boost::python;

    class_<T1>("T1", init<int, double, std::string>())
      .def("__len__", &tuple_length<T1>)
      .def("__getitem__", &get_tuple_item<T1>);

    class_<T2>("T2", init<std::string, int>())
      .def("__len__", &tuple_length<T2>)
      .def("__getitem__", &get_tuple_item<T2>);
}