[C++-sig] Re: How to expose virtual function with default arguments in boost.python ?

David Abrahams dave at boost-consulting.com
Sun Dec 5 00:18:15 CET 2004


Baptiste Lepilleur wrote:

 > I'm basically trying to expose the virtual member function
 > 'set' of the following code:
 >
 > ----
 > class VirtualNonCopyable {
 > public:
 >    virtual void set( const std::string &name_, int size_ = 10, int 
width_ =
 > 12 ) {
 >       name = name_;
 >       size = size_;
 >       width = width_;
 >    }
 >
 >    std::string name;
 >    int size;
 >    int width;
 > };
 >
 > inline VirtualNonCopyable &getVirtualNonCopyable() {
 >    static VirtualNonCopyable instance;
 >    return instance;
 > }
 > ----
 >
 > Pyste generate the following binding code (full source attached):
 >
 > ----
 >     class_< VirtualNonCopyable, py::VirtualNonCopyable_Wrapper
 >
 >>("VirtualNonCopyable", init<  >())
 >
 >         .def("set", &VirtualNonCopyable::set,
 > &py::VirtualNonCopyable_Wrapper::default_set_3)
 >         .def("set", &py::VirtualNonCopyable_Wrapper::default_set_1)
 >         .def("set", &py::VirtualNonCopyable_Wrapper::default_set_2)

<snip>

 > ----
 > Pyste is still using old-style polymorphism. default_set_1, 
default_set_2
 > and default_set_3 are methods forwarding to the base class 
implementation.
 > The binding for default_set_1 should be the one triggered by the 
python code
 > below.
 >
 > The bug is demonstrated by the following python code:
 >
 > object = getVirtualNonCopyable()   # Get a instance of 
VirtualNonCopyable
 > from C++
 > object.set( 'abc' )                # use overloading resolution to 
apply the default values

Right.  The problem here is that all the overloads for handling
default arguments take a first argument of

    py::VirtualNonCopyable_Wrapper {lvalue}

(because they are member functions of VirtualNonCopyable_Wrapper)
but the object you're creating in C++ is only of type

   VirtualNonCopyable {lvalue}

You can see most of this in the overload set described in the error
message below, if you look carefully (using an initial type
other than std::string would make it clearer).

So one way to make it work is to add some functions that can be
called for VirtualNonCopyable objects:

   void set_2(VirtualNonCopyable& self, std::string s, int p1)
   { self.set(s,p1); }

   void set_1(VirtualNonCopyable&& self, std::string s)
   { self.set(s); }

And before any of the other defs (so if the object is actually a
VirtualNonCopyable_Wrapper the other overloads will take
priority), but in any order, you do:

      .def("set", set_1)
      .def("set", set_2)

Alternatively, you should be able to avoid defining any helper
functions this way:

      .def(
          "set"
        , make_function(
              &VirtualNonCopyable::set
            , mpl::vector<void,std::string,int,int>())
      )
      .def(
          "set"
        , make_function(
              &VirtualNonCopyable::set
            , mpl::vector<void,std::string,int>())
      )

Incidentally, all this applies just as well even after you fix
Pyste to use new-style polymorphism.

HTH,

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com




More information about the Cplusplus-sig mailing list