Boost::Python, converting tuple to Python works, vector<tuple> does not Boost::Python, converting tuple to Python works, vector<tuple> does not python python

Boost::Python, converting tuple to Python works, vector<tuple> does not


TupleToPython registers C++-to-Python converters and Python-to-C++ converters. This is fine.

On the other hand, you want your vector elements to be returned by reference. But there's nothing on the Python side that can serve as a reference to your tuple. A converted-to-Python tuple may hold the same values, but it is completely detached from the original C++ tuple.

It looks like in order to export a tuple by reference, one would need to create an indexing suite for it, rather than to/from-Python converters. I have never done that and cannot guarantee it will work.

Here's how one could expose a tuple as a minimal tuple-like Python object (with only len() and indexing). First define some helper functions:

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>::typeget_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>::typeget_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);}

Then expose specific tuples:

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>);}

Note these quasi-tuples, unlike real Python tuples, are mutable (via C++). Because of tuple immutability, exporting via converters and NoProxy looks like a viable alternative to this.