[C++-sig] Re: Converting CString to/from std::string
Martin Blais
blais at iro.umontreal.ca
Wed Sep 24 21:09:50 CEST 2003
Me again.
I wrapped up the ugly bits of the automated conversion to do some of
the cooking automatically. I use it like this, for an hypothetical
MyPath class for which I want to declare automatic conversion to/from
a string (without exposing MyPath)::
template <>
python::object AutoConverter<MyPath>::toObject( MyPath const& s )
{
return python::str( s.cstr() );
}
template <>
void* AutoConverter<MyPath>::convertible( PyObject* obj_ptr )
{
if ( !PyString_Check(obj_ptr) ) return 0;
return obj_ptr;
}
template <>
void AutoConverter<MyPath>::fromPython(
PyObject* obj_ptr,
void* memblock
)
{
const char* value = PyString_AsString( obj_ptr );
if (value == 0) {
python::throw_error_already_set();
}
new ( memblock ) MyPath( value );
}
Then in my initmodule definition I add::
...
AutoConverter<MyPath>();
...
I tested this with MSVC7.1 (2003/.NET) on Windows XP. Works for me,
does the gig for now.
But somehow, I feel like I'm not doing something right, there must be
a better way to do this. I'm sure Dave thought about some way for
automatic conversions to occur but I am not finding it.
The template file that wraps this up is attached.
(Dave: feel free to massage and include the file in attachment to
Boost.Python, if you think it's worth anything.)
comments appreciated.
cheers,
Martin Blais wrote:
> 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
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: caba.cpp
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20030924/b4aeac6c/attachment.txt>
More information about the Cplusplus-sig
mailing list