Собственное использование строк

c #python #boost #export

#c #python #повышение #экспорт

Вопрос:

У меня есть свой собственный класс string, и я хочу экспортировать его в python (с помощью boost.python) и использовать как собственную строку. Я написал конвертеры для этого.

Первый — это экспорт моей строки:

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

Конвертеры взяты из учебника по умолчанию, но с моим типом:

 // CL_StringRef8 → Python string --------------------------------------
struct cl_stringref8_to_python_str
{
    static PyObject* convert(CL_StringRef8 constamp; 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(
            amp;convertible,
            amp;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;
    }
};
 

Теперь, как я понимаю, я могу вызывать функции c из python, которые принимают аргументы CL_StringRef8 , но у меня есть код:

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

# ==>

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

Насколько я понимаю, мне нужно экспортировать str() метод для CL_StringRef8 , но я не могу этого сделать:

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

Последняя строка вызывает ошибку:

 /usr/include/boost/lexical_cast.hpp: In member function ‘bool boost::detail::lexical_stream<Target, Source, Traits>::operator<<(const Sourceamp;) [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_StringRef8amp;, std::size_t = long unsigned int]’
/usr/include/boost/lexical_cast.hpp:1174:77:   instantiated from ‘Target boost::lexical_cast(const Sourceamp;) [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_tamp;) [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(ClassTamp;) 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 Vamp;, classTamp;) [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(classTamp;) 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>::selfamp; boost::python::class_<T, X1, X2, X3>::def(const boost::python::def_visitor<Derived>amp;) [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>amp;amp;’
/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>amp; std::operator<<(std::basic_ostream<_CharT, _Traits>amp;amp;, const _Tpamp;) [with _CharT = char, _Traits = std::char_traits<char>, _Tp = CL_StringRef8]’
 

ps и да, я не забыл зарегистрировать свои конвертеры в python.

Комментарии:

1. Интересно, что было не так с std::basic_string тем, что ваш класс работает лучше? Если вы не можете назначить свою строку std::string , вы не сможете использовать такие реализации, как boost::lexical_cast с вашим классом string. Вам необходимо обеспечить совместимость с алгоритмами STL, итераторами и т. Д., А также с преобразованиями.

Ответ №1:

Для того, чтобы .def(bp::self_ns::str(bp::self_ns::self)); строка работала, вам необходимо определить оператор потоковой передачи для вашего класса.

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

Альтернативный способ определения метода str() без использования оператора потоковой передачи:

 .def("__str__", amp;CL_StringRef8::c_str) 
 

Хотя я предпочитаю просто использовать метод repr() вместо этого, который затем используется str() при необходимости

 .def("__repr__", amp;CL_StringRef8::c_str)  
 

Все это все равно не заставит float() работать в Python, поскольку он ожидает либо строку (не объект, даже если он поддерживает __str__ ), либо float, либо объект, который поддерживает __float__ .

Однако мы можем сделать последнее, связав lexical_cast с вашим методом c_str():

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

и затем

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

Теперь вы можете сделать это на Python:

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