17 votes

Boost Python Pas de convertisseur to_python trouvé pour std::string

J'essaie donc de créer un convertisseur to_python qui me permettra de renvoyer un boost::optional à partir d'une fonction exposée et de le faire traiter comme T si l'optional est défini et None sinon. En me basant sur un post que j'ai trouvé sur C++Sig J'ai donc écrit le code suivant.

template<typename T>
struct optional_ : private boost::noncopyable {
  struct conversion {
    static PyObject* convert(boost::optional<T> const& value) {
      if (value) {
        return boost::python::to_python_value<T>()(*value);
      }
      Py_INCREF(Py_None);
      return Py_None;
    }
  };
  explicit optional_() {
    boost::python::to_python_converter<boost::optional<T>, conversion>();
  }
};

Pour autant que je puisse en juger, cela fonctionne pour convertir les options, mais python lance l'exception suivante "TypeError : No to_python (by-value) converter found for C++ type : std::string". Je sais que le C++ est capable de convertir des chaînes en python puisque la plupart de mes fonctions exposées renvoient des chaînes. Pourquoi boost::python::to_python_value ne le reconnaît-il pas, et comment puis-je utiliser le convertisseur qu'il possède ?

Corrigé en remplaçant le texte par le suivant (basé sur cet article ) :

template<typename T>
struct optional_ : private boost::noncopyable {
  struct conversion {
    static PyObject* convert(boost::optional<T> const& value) {
      using namespace boost::python;
      return incref((value ? object(*value) : object()).ptr());
    }
  };
  explicit optional_() {
    boost::python::to_python_converter<boost::optional<T>, conversion>();
  }
};

Il ne reste plus qu'à faire l'autre version pour qu'elle soit plus propre et qu'elle fonctionne mieux.

4voto

DRayX Points 451

Ok voici le convertisseur optionnel complet basé sur le post original de C++ sig mais réécrit pour utiliser l'API boost.python de haut niveau (désolé pour l'espacement bizarre).

template<typename T>
struct optional_ : private boost::noncopyable
{
  struct conversion :
    public boost::python::converter::expected_from_python_type<T>
  {
    static PyObject* convert(boost::optional<T> const& value) {
      using namespace boost::python;
      return incref((value ? object(*value) : object()).ptr());
    }
  };

  static void* convertible(PyObject *obj) {
    using namespace boost::python;
    return obj == Py_None || extract<T>(obj).check() ? obj : NULL;
  }

  static void constructor(PyObject *obj,
       boost::python::converter::rvalue_from_python_stage1_data *data)
  {
    using namespace boost::python;
    void *const storage =
      reinterpret_cast<
        converter::rvalue_from_python_storage<boost::optional<T> >*
      >(data)->storage.bytes;
    if(obj == Py_None) {
      new (storage) boost::optional<T>();
    } else {
      new (storage) boost::optional<T>(extract<T>(obj));
    }
    data->convertible = storage;
  }

  explicit optional_() {
    using namespace boost::python;
    if(!extract<boost::optional<T> >(object()).check()) {
      to_python_converter<boost::optional<T>, conversion, true>();
      converter::registry::push_back(
        &convertible,
        &constructor,
        type_id<boost::optional<T> >(),
        &conversion::get_pytype
      );
    }
  }
};

1voto

Pixie-Poop Points 21

Il y a quelques fautes de frappe dans le code ci-dessus - voici la version corrigée :

#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
#include <boost/python.hpp>

template<typename T>
struct python_optional : private boost::noncopyable {
  struct conversion : public boost::python::converter::expected_from_python_type<T>
  {
    static PyObject* convert(boost::optional<T> const& value)
    {
      using namespace boost::python;
      return incref((value ? object(*value) : object()).ptr());
    }
  };

  static void* convertible(PyObject *obj) {
    using namespace boost::python;
    return obj == Py_None || extract<T>(obj).check() ? obj : NULL;
  }

  static void constructor(
    PyObject *obj,
    boost::python::converter::rvalue_from_python_stage1_data *data
  ) {
    using namespace boost::python;
    void *const storage =
      reinterpret_cast<
        converter::rvalue_from_python_storage<boost::optional<T> >*
      >(data)->storage.bytes;
    if(obj == Py_None) {
      new (storage) boost::optional<T>();
    } else {
      new (storage) boost::optional<T>(extract<T>(obj));
    }
    data->convertible = storage;
  }

  explicit python_optional() {
    using namespace boost::python;
    if(!extract<boost::optional<T> >(object()).check()) {
      to_python_converter<boost::optional<T>, conversion, true>();
      converter::registry::push_back(
        &convertible,
        &constructor,
        type_id<boost::optional<T> >(),
        &conversion::get_pytype
      );
    }
  }
};

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X