2011-05-31 3 views
2

J'ai mon own string class et je veux l'exporter en python (avec boost.python) et l'utiliser comme une chaîne native. J'ai écrit des convertisseurs pour cela.Utilisation de la chaîne propre

Le premier est l'exportation de ma chaîne:

bp::class_<CL_StringRef8>("CL_StringRef8", bp::init<const std::string&>()) 
    .def("CStr", &CL_StringRef8::c_str); 

Les convertisseurs sont de tutoriel par défaut, mais avec mon type:

// CL_StringRef8 → Python string -------------------------------------- 
struct cl_stringref8_to_python_str 
{ 
    static PyObject* convert(CL_StringRef8 const& s) 
    { 
     return boost::python::incref(boost::python::object(s.c_str()).ptr()); 
    } 
}; 

// Python string → CL_StringRef8 -------------------------------------- 
struct cl_stringref8_from_python_str 
{ 
    cl_stringref8_from_python_str() 
    { 
     bp::converter::registry::push_back(
      &convertible, 
      &construct, 
      boost::python::type_id<CL_StringRef8>() 
     ); 
    } 

    static void* convertible(PyObject* obj_ptr) 
    { 
     if (!PyString_Check(obj_ptr)) return 0; 
     return obj_ptr; 
    } 

    static void construct(PyObject* obj_ptr, bp::converter::rvalue_from_python_stage1_data* data) 
    { 
     const char* value = PyString_AsString(obj_ptr); 
     if (value == 0) bp::throw_error_already_set(); 
     void* storage = ((bp::converter::rvalue_from_python_storage<CL_StringRef8>*)data)->storage.bytes; 
     new (storage) CL_StringRef8(value); 
     data->convertible = storage; 
    } 
}; 

Maintenant, ce que je comprends, je peux appeler c fonctions ++ de python qui prend en arguments CL_StringRef8, mais j'ai un code:

print GetMyStringObject() 
data = float(GetMyStringObject()) 

# ==> 

<CL_StringRef object at 0x7fd15dfd9de8> 
TypeError: float() argument must be a string or a number 

Comme je comprends que je doivent exporter str() méthode de CL_StringRef8 mais je ne peux pas le faire:

bp::class_<CL_StringRef8>("CL_StringRef8", bp::init<const std::string&>()) 
    .def("CStr", &CL_StringRef8::c_str) 
    .def(bp::self_ns::str(bp::self_ns::self)); 

La dernière ligne appelle une erreur:

/usr/include/boost/lexical_cast.hpp: In member function ‘bool boost::detail::lexical_stream<Target, Source, Traits>::operator<<(const Source&) [with Target = std::basic_string<char>, Source = CL_StringRef8, Traits = std::char_traits<char>]’: 
/usr/include/boost/lexical_cast.hpp:1151:13: instantiated from ‘Target boost::detail::lexical_cast(typename boost::call_traits<Source>::param_type, CharT*, std::size_t) [with Target = std::basic_string<char>, Source = CL_StringRef8, bool Unlimited = true, CharT = char, typename boost::call_traits<Source>::param_type = const CL_StringRef8&, std::size_t = long unsigned int]’ 
/usr/include/boost/lexical_cast.hpp:1174:77: instantiated from ‘Target boost::lexical_cast(const Source&) [with Target = std::basic_string<char>, Source = CL_StringRef8]’ 
/usr/include/boost/python/operators.hpp:357:1: instantiated from ‘static PyObject* boost::python::detail::operator_1<(boost::python::detail::operator_id)19u>::apply<T>::execute(boost::python::detail::operator_1<(boost::python::detail::operator_id)19u>::apply<T>::self_t&) [with T = CL_StringRef8, PyObject = _object, boost::python::detail::operator_1<(boost::python::detail::operator_id)19u>::apply<T>::self_t = CL_StringRef8]’ 
/usr/include/boost/python/operators.hpp:152:11: instantiated from ‘void boost::python::detail::operator_<id, L, R>::visit(ClassT&) const [with ClassT = boost::python::class_<CL_StringRef8>, boost::python::detail::operator_id id = (boost::python::detail::operator_id)19u, L = boost::python::detail::not_specified, R = boost::python::detail::not_specified]’ 
/usr/include/boost/python/def_visitor.hpp:31:9: instantiated from ‘static void boost::python::def_visitor_access::visit(const V&, classT&) [with V = boost::python::def_visitor<boost::python::detail::operator_<(boost::python::detail::operator_id)19u> >, classT = boost::python::class_<CL_StringRef8>]’ 
/usr/include/boost/python/def_visitor.hpp:67:9: instantiated from ‘void boost::python::def_visitor<DerivedVisitor>::visit(classT&) const [with classT = boost::python::class_<CL_StringRef8>, DerivedVisitor = boost::python::detail::operator_<(boost::python::detail::operator_id)19u>]’ 
/usr/include/boost/python/class.hpp:225:9: instantiated from ‘boost::python::class_<T, X1, X2, X3>::self& boost::python::class_<T, X1, X2, X3>::def(const boost::python::def_visitor<Derived>&) [with Derived = boost::python::detail::operator_<(boost::python::detail::operator_id)19u>, W = CL_StringRef8, X1 = boost::python::detail::not_specified, X2 = boost::python::detail::not_specified, X3 = boost::python::detail::not_specified, boost::python::class_<T, X1, X2, X3>::self = boost::python::class_<CL_StringRef8>]’ 
/home/ockonal/Workspace/Themisto/src/Scripts/Core/TypesConverters.cpp:375:49: instantiated from here 
/usr/include/boost/lexical_cast.hpp:595:48: error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’ 
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.6.0/../../../../include/c++/4.6.0/ostream:581:5: error: initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits<char>, _Tp = CL_StringRef8]’ 

ps et oui, je ne pas oublier enregistrer mes convertisseurs en python.

+2

Intéressant ce qui n'allait pas avec 'std :: basic_string' que votre classe fait mieux? Si vous ne pouvez pas affecter votre chaîne à 'std :: string', vous ne pouvez pas utiliser des implémentations telles que' boost :: lexical_cast' avec votre classe de chaînes. Vous devrez fournir une compatibilité avec les algorithmes STL, les itérateurs, etc. ainsi que les conversions. – AJG85

Répondre

2

Pour que la ligne .def(bp::self_ns::str(bp::self_ns::self)); fonctionne, vous devez définir l'opérateur de diffusion en continu pour votre classe.

std::ostream & operator<<(std::ostream & os, const CL_StringRef8 &s) 
{ os << s.c_str(); return os; } 

Une autre façon de définir la méthode str() sans avoir besoin de l'opérateur de diffusion en continu est:

.def("__str__", &CL_StringRef8::c_str) 

Bien que, je préfère faire exactement la méthode rééd() au lieu qui est ensuite utilisé par str() en cas de besoin

.def("__repr__", &CL_StringRef8::c_str) 

Tout cela ne sera pas toujours faire float() en Python, car il attend soit une chaîne (pas un objet, même si elle prend en charge __str__), un flotteur ou un obje ct qui prend en charge __float__.

Nous pouvons faire ce dernier si, en liant un lexical_cast autour de votre méthode c_str():

#include <boost/lexical_cast.hpp> 
#include <boost/mpl/vector.hpp> 

puis

.def("__float__", bp::make_function( 
        boost::bind(&boost::lexical_cast<float,CL_StringRef8>,_1), 
         bp::default_call_policies(), 
         boost::mpl::vector<float,CL_StringRef8>())); 

Maintenant, vous pouvez le faire en Python:

>>> a = CL_StringRef8("1.234") 
>>> print a 
1.234 
>>> float(a) * 2 
2.468 
+0

Merci pour la réponse;) – Ockonal

Questions connexes