Używam Boost :: Python przez jakiś czas, a wszystko zawsze było ok. Jednak wczoraj próbowałem dowiedzieć się, dlaczego dany typ, który myślałem, że zarejestrowałem (krotka) dawał mi błędy, gdy próbowałem uzyskać do niego dostęp z Pythona.Boost :: Python, konwersja krotki do prac w Pythonie, wektor <tuple> nie
Okazuje się, że podczas gdy krotka była rzeczywiście zarejestrowana, próbując uzyskać do niej dostęp poprzez std::vector
zapakowaną przez vector_indexing_suite
, to już nie wystarczy.
Zastanawiam się, dlaczego to nie działa? Czy jest jakiś sposób, aby to zadziałało? Czy powinienem spróbować ręcznie owijać wektor?
Poniżej jest moje 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);
}
Dostęp wynikowy .so
pośrednictwem wyników Pythona w:
>>> print makeMyTuple()
(0,)
>>> print makeTuples()[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: No Python class registered for C++ class std::tuple<int>
>>>
EDIT: zdałem sobie sprawę, że błąd nie zdarza się w przypadku stosowania vector_indexing_suite
z parametrem NoProxy
ustawionym na true. Jednak wolałbym, gdyby nie było to konieczne, ponieważ powoduje, że wyeksportowane klasy są nieintuicyjne w Pythonie.
nie powinien "Tuple makeTuples() { return Tuples {MyTuple()}; } 'be' Tuples makeTuples() { return Krotki(); } zamiast tego? – fedepad
@fedepad Zrobiłem to, abyś mógł wywołać 'makeTuples() [0]' bez wywoływania błędu 'out_of_bounds', ponieważ wtedy wektor byłby pusty i nie zobaczyłbyś błędu krotki. – Svalorzen