Boost::Python, converting tuple to Python works, vector<tuple> does not
Boost::Python, converting tuple to Python works, vector
--
Become part of the top 3% of the developers by applying to Toptal
https://topt.al/25cXVn
--
Music by Eric Matyas
https://www.soundimage.org
Track title: Realization
--
Chapters
00:00 Question
02:11 Accepted answer (Score 2)
04:12 Thank you
--
Full question
https://stackoverflow.com/questions/4218...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #c++ #boost #tuples #boostpython
#avk47
ACCEPTED ANSWER
Score 2
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>::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);
}
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.