[C++-sig] Re: IntWrapper.hpp in indexing_suite

Raoul Gough RaoulGough at yahoo.co.uk
Sun Oct 12 19:22:04 CEST 2003


"Niall Douglas" <s_sourceforge at nedprod.com> writes:

> On 11 Oct 2003 at 12:14, Raoul Gough wrote:
>
>> I've used IntWrapper in a number of different test cases, and ISTR one
>> of them needed a conversion to shared pointer. I suspect that test
>> didn't make it into the CVS, so the shared pointer conversion is
>> currently redundant.
>
> Right, sorry, as I mentioned before I don't quite get how all this 
> works ...
>
>> I don't think the shared pointer conversion has anything to do with
>> this. The really important bit is this:
>> 
>>   boost::python::class_<IntWrapper> ("IntWrapper",
>>   boost::python::init<int>())
>>     .def ("increment", &IntWrapper::increment)
>>     .def ("__repr__", repr)
>>     .def ("__cmp__", compare)
>>     ;
>> 
>> which turns IntWrapper into a Python class, with enough support to
>> convert it to a string and compare two IntWrapper objects. There is
>> also an implicit conversion from int, which means that code like this
>> will work:
>
> Hang on, back up a way bit. Firstly, you appear to be implying that 
> the sequence in python is actually of IntWrapper's, not real int's. 
> Actually, now that looks obvious, but I hadn't realised that before.
>
> Therefore the down conversion from an IntWrapper to an int is 
> happening when python pulls a value /from/ the sequence eg; 
> repr(sequence).

I don't think that Python ever converts the IntWrapper to an int - the
__repr__ method returns a string. Although the int member variable is
publically visible, AFAIR there isn't any external code that accesses
it.

>
> Ok, I now get why there's the __cmp__ and __repr__. But why the 
> increment()? Surely that should be __inc__ or something? (I can't 
> find __inc__ anywhere in the python docs. But it can't be a reference 
> count as there's no way of reading it, decrementing it and besides, 
> it's incrementing the value, not a refCount).

As you surmise, the increment doesn't have anything to do with the
reference counting. It's just a minimal mutation function to
facilitate checking whether two Python objects refer to the same
IntWrapper object or not - the tests typically call obj1.increment()
and check whether the values of obj1 and obj2 are still identical
after the change. That's really the main reason to have IntWrapper (or
int_wrapper as it will soon be called) apart from the optional
tracing, which isn't currently used.

>
> Actually, how the hell is bpl converting an IntWrapper to an int? I 
> understand how int becomes IntWrapper (the explicit copy 
> constructor), but not vice versa!
>
>> > 	CArrayMember<std::string> 
>> > *data=static_cast<CArrayMember<std::string> *>(l.getData());
>> 
>> Wow. This is almost certainly undefined behaviour.
>
> Might be according to the standard, but if CArrayMember<> contains no 
> data members, there's no chance of copy slicing and thus no problem.

I guess it would be pretty surprising for the types to have different
layouts or sizes if you don't add any more data members. I think the
risk exists in theory at least, so other compilers or compiler options
might break the code. There is also the (maybe not so theoretical)
risk that somebody accidentally adds a member variable to the class
template.

>
>> > 	return 
>> > boost::python::indexing::iterator_pair<CArrayMember<std::string> *>
>> > 		(data, data+100000); // Issue if l is near the 4Gb mark
>> > }
>> 
>> The bounds checking code will still be compiled, of course, so lying
>> about the bound doesn't actually gain you anything (unless you have no
>> way of figuring out the real bound). You should be able to provide the
>> correct bound without too much trouble in this example.
>
> Yeah twas temporary code I'll fix later. I was going to have a 
> template parameter take an address to a function which when called, 
> returns the length of the array (seeing as that function varies 
> between classes). And a template specialisation taking arrays with 
> length attached.

Ah ha. Now it makes sense.

>
>> OK, so CArrayMember<std::string> is-a std::string. You still haven't
>> exposed it to Python though. You will need something like this:
>> 
>> class_<CArrayMember<std::string>, bases<std::string> >
>>    ("CArrayMember_string");
>> 
>> I don't know exactly what else you'll have to do here - maybe define
>> implicit conversions to/from std::string, maybe make it no_init. The
>> container suite doesn't attempt to expose the container's value type
>> to Python - it assumes that you will do that yourself. I would suggest
>> first trying to get CArrayMember<...> working in Python before trying
>> to expose a container of CArrayMembers.
>
> I had been assuming that std::string already has a registered 
> converter converting it to a python string.

Yes, it does. I hadn't really thought this through before, but the
implicit conversion from derived to base must mean that Boost.Python
can already return the string portion of the object to Python. This
may result in object slicing if you're returning the object by value,
though (I guess not a problem in this case).

>
> But what's *very* important to understand here is that soon I'll
> make the std::string a template parameter as I want it to be
> generically applicable ie; you can wrap any C++ object with the
> necessary gumph to make it a member of a sequence.
>
> Ideally however I'd like to somehow divorce the conversion of the
> types in the array from the accessing of the array. The conversions
> are already registered and mapped to python types - my CArray code
> should merely index the array and return a type (often pointer to
> type) to the array member which then BPL converts as it would
> normally do (when returned from a method) to its corresponding
> python type.

Sounds alright to me.

-- 
Raoul Gough.
(setq dabbrev-case-fold-search nil)





More information about the Cplusplus-sig mailing list