J'utilise Boost::Python depuis un certain temps, et tout s'est toujours bien passé. Cependant, hier, j'ai essayé de comprendre pourquoi un type particulier que je pensais avoir enregistré (un tuple) me donnait des erreurs lorsque j'essayais d'y accéder depuis Python.
Il s'avère que, bien que le tuple ait été enregistré, lorsque l'on tente d'y accéder par le biais d'un fichier de type std::vector
enveloppé par l'intermédiaire du vector_indexing_suite
ce n'est plus suffisant.
Je me demandais, pourquoi ça ne marche pas ? Y a-t-il un moyen de le faire fonctionner ? Dois-je essayer d'envelopper le vecteur à la main ?
Voici mon 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);
}
Accès au résultat .so
via Python résulte en :
>>> 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 : Je me suis rendu compte que l'erreur ne se produit pas si le fichier vector_indexing_suite
est utilisé avec le NoProxy
défini comme vrai. Cependant, je préférerais que cela ne soit pas nécessaire, car cela rend les classes exportées peu intuitives en Python.