Roman Yakovenko wrote:
> Can you create relevant test cases and send them to me? I will add the
> code that fixes it.
Here is an example class that contains three of the problems mentioned:
///////////////////////////////////////////////////////
// File: source.h
class Foo
{
public:
// When keywords are disabled, the arguments of this constructor
// are not optional anymore in the Python bindings
Foo(double x, double y=0, double z=0);
// The copy constructor is not wrapped
Foo(const Foo& f);
// The index operator is not wrapped
int operator[](int idx);
};
///////////////////////////////////////////////////////
I was still using my own version of the API using these lines:
from pyppapi import *
header("source.h")
parse()
Constructor().disableKeywordArgs()
writeFiles()
So I did nothing special except for disabling the keywords on the
constructor. The generated code looks like this:
void register_Foo_class(){
bp::class_< Foo >( "Foo", bp::init< double, double, double
>()[bp::default_call_policies()] );
}
There are three things to note:
- The optional values in the first constructor are not optional anymore
whereas they could be made optional using init< double, optional<double,
double> >()
- The copy constructor does not appear in the bindings
- The index operator does not appear in the bindings (Pyste also ignores
this operator. Is there an issue with that? Couldn't this just used as
implementation for the __getitem__ method?)
Here is another example showing the enum problem when the cache is used:
///////////////////////////////////////////////////////
class Foo
{
public:
enum Color { red, green, blue, black, white };
};
///////////////////////////////////////////////////////
I was using the following code to wrap the class:
from pyppapi import *
header("source.h")
cache("pypp.cache")
writeFiles()
Again, nothing special except for enabling the cache.
The generated code looks like this:
void register_Foo_class(){
if( true ){
typedef bp::class_< Foo > Foo_exposer_t;
Foo_exposer_t Foo_exposer = Foo_exposer_t( "Foo" );
bp::scope Foo_scope( Foo_exposer );
bp::enum_<Foo::Color>("Color")
.value("blue", Foo::blue)
.value("green", Foo::green)
.value("white", Foo::white)
.value("black", Foo::black)
.value("red", Foo::red)
.export_values()
;
}
}
When I create the bindings a second time, the order of the enum values
is blue-black-white-green-red. These two orderings always switch back
and forth with each invocation of pyplusplus which means the file always
changes and gets recompiled every time.
I think it would be nice if the order could actually be that of the
source file (which also isn't the case even when the cache is not used).
The thing about the friend functions was my fault (sort of). When I
wanted to set up a simple example I noticed that pyplusplus actually
supports those friend functions but the problem is that the declaration
does not appear as children of the class declaration. That's why I was
ignoring them (I'm ignoring everything by default and then add the
classes I want to wrap).
I'd argue that the declarations for operators implemented as friend
functions should also appear as children of the corresponding class
declaration as in the Python bindings they have to be part of the class.
Otherwise I don't see a straightforward way to address these operators
for calling ignore()/expose() on them.
- Matthias -