[C++-sig] Re: Converting CString to/from std::string

Martin Blais blais at iro.umontreal.ca
Tue Sep 23 22:27:08 CEST 2003


Hi guys

I just found the mail below, answers one of my questions, and
AFAIK the answer for my query is not clearly there in the
Boost.Python docos.  In fact, porting code from v1 to v2, I
think that this should be in the FAQ for the following
question:

   "How do I register automatic conversions to/from a specific
    C++ class without exposing the C++ class itself to the
    Python interface?"

in v1, I used to do with by declaring to_python and from_python
converter methods in the appropriate namespace.  The C++ class
that was converted was not known to the Python interface at
all.  I think the example below seems to address my query, I
tried it and it works.

It would be nice to add this capability to the FAQ or docs.

also, maybe I'm going about this wrong, but it seems to perform
this task in v1 was cleaner... is there a better way?  I'm sure
there must be but I just didn't find it.

If there is no better way, some C++ code magic to wrap this up
and make it look nicer would be a desired feature IMHO.

Note that I wouldn't mind wrapping up and exposing the class
instead, if the implicit converters would always be triggered
such that my users never have to be aware of the existence of
the corresponding C++ class; I tried changing my C++ class to
add implicit conversions but it doesn't get triggered somehow,
here is an example, with a MyPath class that I would like to
be automatically convertible from/to a Python string::

   class MyPath {

   public:

      /*----- member functions -----*/

      MyPath();
      MyPath( const char* );
      operator const char* ();

    ...

In initmodule:

    class_<MyPath> clsMyPath( "MyPath", init<const char*>() );
    implicitly_convertible<const char*, MyPath>();


Then from Python calling::

   objin('/some/path')


Which is supposed to be able to call a function wrapped in C++::

   void objin( MyPath a ) const


I get::

   Traceback (most recent call last):
     File "c:/tmp/aaa", line 16, in ?
       a.objin('/some/path')
   Boost.Python.ArgumentError: Python argument types in
       ClassA.objin(ClassA, str)
   did not match C++ signature:
       objin(class Dl::PyextModuleA::ClassA {lvalue}, class 
Dl::PyextModuleA::MyPath)


Also, if my function takes a ``const MyPath&``, it behaves the
same (but I did not expect this one to work though).


any info greatly appreciated.

cheers,








Ralf W. Grosse-Kunstleve wrote:
> --- Kirsebom Nikolai <nikolai.kirsebom at siemens.no> wrote:
> 
>>Some time ago I made a 'socket based' system (using BISON/FLEX for parsing)
>>where I expose C++ objects to python.  In this system CStrings are regular
>>Python strings.
> 
> 
> Attached is a small, self-contained demo extension module that shows how to do
> what you want. Here is the corresponding trivial regression test:
> 
> from sandbx_boost import custom_string
> assert custom_string.hello() == "Hello world."
> assert custom_string.size("california") == 10
> 
> If you look at the code you will find:
> 
> 1. A custom to_python converter (easy): custom_string_to_python_str
> 
> 2. A custom lvalue converter (needs more code): custom_string_from_python_str
> 
> The custom converters are registered in the global Boost.Python registry near
> the top of the module initialization function. Once flow control has passed
> through the registration code the automatic conversions from and to Python
> strings will work in any module imported in the same process.
> 
> HTH,
>         Ralf
> 
> #include <boost/python/module.hpp>
> #include <boost/python/def.hpp>
> #include <boost/python/to_python_converter.hpp>
> 
> namespace sandbx { namespace {
> 
>   class custom_string
>   {
>     public:
>       custom_string() {}
>       custom_string(std::string const& value) : value_(value) {}
>       std::string const& value() const { return value_; }
>     private:
>       std::string value_;
>   };
> 
>   struct custom_string_to_python_str
>   {
>     static PyObject* convert(custom_string const& s)
>     {
>       return boost::python::incref(boost::python::object(s.value()).ptr());
>     }
>   };
> 
>   struct custom_string_from_python_str
>   {
>     custom_string_from_python_str()
>     {
>       boost::python::converter::registry::push_back(
>         &convertible,
>         &construct,
>         boost::python::type_id<custom_string>());
>     }
> 
>     static void* convertible(PyObject* obj_ptr)
>     {
>       if (!PyString_Check(obj_ptr)) return 0;
>       return obj_ptr;
>     }
> 
>     static void construct(
>       PyObject* obj_ptr,
>       boost::python::converter::rvalue_from_python_stage1_data* data)
>     {
>       const char* value = PyString_AsString(obj_ptr);
>       if (value == 0) boost::python::throw_error_already_set();
>       void* storage = (
>         (boost::python::converter::rvalue_from_python_storage<custom_string>*)
>           data)->storage.bytes;
>       new (storage) custom_string(value);
>       data->convertible = storage;
>     }
>   };
> 
>   custom_string hello() { return custom_string("Hello world."); }
> 
>   std::size_t size(custom_string const& s) { return s.value().size(); }
> 
>   void init_module()
>   {
>     using namespace boost::python;
> 
>     boost::python::to_python_converter<
>       custom_string,
>       custom_string_to_python_str>();
> 
>     custom_string_from_python_str();
> 
>     def("hello", hello);
>     def("size", size);
>   }
> 
> }} // namespace sandbx::<anonymous>
> 
> BOOST_PYTHON_MODULE(custom_string)
> {
>   sandbx::init_module();
> }
> 
> 
> __________________________________
> Do you Yahoo!?
> The New Yahoo! Search - Faster. Easier. Bingo.
> http://search.yahoo.com






More information about the Cplusplus-sig mailing list