From ff9f262fac190f7fd31f6476e756ed4b88976368 Mon Sep 17 00:00:00 2001 From: Joel de Guzman Date: Tue, 18 Feb 2003 18:44:16 +0000 Subject: [PATCH] tutorial update [SVN r17512] --- doc/tutorial/doc/basic_interface.html | 16 +- doc/tutorial/doc/building_hello_world.html | 2 +- doc/tutorial/doc/call_policies.html | 32 ++-- doc/tutorial/doc/class_data_members.html | 17 +- .../class_operators_special_functions.html | 26 +-- doc/tutorial/doc/class_properties.html | 22 ++- doc/tutorial/doc/class_virtual_functions.html | 83 +++++---- doc/tutorial/doc/constructors.html | 28 +-- doc/tutorial/doc/default_arguments.html | 86 +++++++--- doc/tutorial/doc/derived_object_types.html | 30 ++-- doc/tutorial/doc/enums.html | 24 +-- doc/tutorial/doc/exception_translation.html | 10 +- doc/tutorial/doc/exposing_classes.html | 22 +-- doc/tutorial/doc/extracting_c___objects.html | 10 +- doc/tutorial/doc/functions.html | 2 +- doc/tutorial/doc/inheritance.html | 16 +- doc/tutorial/doc/iterators.html | 18 +- doc/tutorial/doc/object_interface.html | 8 +- doc/tutorial/doc/overloading.html | 152 +++++++++++++++++ doc/tutorial/doc/quickstart.html | 10 +- doc/tutorial/doc/quickstart.txt | 161 +++++++++++++++++- doc/tutorial/index.html | 7 +- 22 files changed, 561 insertions(+), 221 deletions(-) create mode 100644 doc/tutorial/doc/overloading.html diff --git a/doc/tutorial/doc/basic_interface.html b/doc/tutorial/doc/basic_interface.html index a9326c80..8165b121 100644 --- a/doc/tutorial/doc/basic_interface.html +++ b/doc/tutorial/doc/basic_interface.html @@ -34,7 +34,7 @@ To illustrate, this Python code snippet:

     def f(x, y):
          if (y == 'foo'):
-             x[3:7] = 'bar'
+             x[3:7] = 'bar'
          else:
              x.items += y(3, x)
          return x
@@ -45,16 +45,16 @@ To illustrate, this Python code snippet:

Can be rewritten in C++ using Boost.Python facilities this way:

-    object f(object x, object y) {
+    object f(object x, object y) {
          if (y == "foo")
-             x.slice(3,7) = "bar";
+             x.slice(3,7) = "bar";
          else
-             x.attr("items") += y(3, x);
+             x.attr("items") += y(3, x);
          return x;
-    }
-    object getfunc() {
+    }
+    object getfunc() {
         return object(f);
-    }
+    }
 

Apart from cosmetic differences due to the fact that we are writing the @@ -68,7 +68,7 @@ coder.


-


-

-    >>> x = f(y, z) #x refers to some C++ X
+    >>> x = f(y, z) ##x refers to some C++ X
     >>> del y
-    >>> x.some_method() #CRASH!
+    >>> x.some_method() ##CRASH!
 

What's the problem?

@@ -53,10 +53,10 @@ What's the problem?

Well, what if f() was implemented as shown below:

     X& f(Y& y, Z* z)
-    {
+    {
         y.z = z;
         return y.x;
-    }
+    }
 

The problem is that the lifetime of result X& is tied to the lifetime @@ -70,8 +70,8 @@ Here's what's happening:

  1. f is called passing in a reference to y and a pointer to z
  2. A reference to y.x is returned
  3. y is deleted. x is a dangling reference
  4. x.some_method() is called
  5. BOOM!

We could copy result into a new object:

-    >>> f(y, z).set(42) #Result disappears
-    >>> y.x.get()       #No crash, but still bad
+    >>> f(y, z).set(42) ##Result disappears
+    >>> y.x.get()       ##No crash, but still bad
     3.14
 

@@ -84,25 +84,25 @@ Our problems do not end there. Suppose Y is implemented as follows:

struct Y { X x; Z* z; - int z_value() { return z->value(); } - }; + int z_value() { return z->value(); } + };

Notice that the data member z is held by class Y using a raw pointer. Now we have a potential dangling pointer problem inside Y:

-    >>> x = f(y, z) #y refers to z
-    >>> del z       #Kill the z object
-    >>> y.z_value() #CRASH!
+    >>> x = f(y, z) ##y refers to z
+    >>> del z       ##Kill the z object
+    >>> y.z_value() ##CRASH!
 

For reference, here's the implementation of f again:

     X& f(Y& y, Z* z)
-    {
+    {
         y.z = z;
         return y.x;
-    }
+    }
 

Here's what's happening:

@@ -113,7 +113,7 @@ are our friends:

     def("f", f,
         return_internal_reference<1,
-            with_custodian_and_ward<1, 2> >());
+            with_custodian_and_ward<1, 2> >());
 

What are the 1 and 2 parameters, you ask?

@@ -138,7 +138,7 @@ or more policies can be composed by chaining. Here's the general syntax:

     policy1<args...,
         policy2<args...,
-            policy3<args...> > >
+            policy3<args...> > >
 

Here is the list of predefined call policies. A complete reference detailing @@ -160,7 +160,7 @@ here.


-

     struct Var
     {
-        Var(std::string name) : name(name), value() {}
+        Var(std::string name) : name(name), value() {}
         std::string const name;
         float value;
-    };
+    };
 

Our C++ Var class and its data members can be exposed to Python:

     class_<Var>("Var", init<std::string>())
-        .def_readonly("name", &Var::name)
-        .def_readwrite("value", &Var::value);
+        .def_readonly("name", &Var::name)
+        .def_readwrite("value", &Var::value);
 

-Then, in Python:

+Then, in Python, assuming we have placed our Var class inside the namespace +hello as we did before:

-    >>> x = Var('pi')
-    >>> x.value = 3.14
+    >>> x = hello.Var('pi')
+    >>> x.value = 3.14
     >>> print x.name, 'is around', x.value
     pi is around 3.14
 
@@ -68,7 +69,7 @@ as read-write.


-

Consider a file position class FilePos and a set of operators that take on FilePos instances:

-    class FilePos { /*...*/ };
+    class FilePos { /*...*/ };
 
     FilePos     operator+(FilePos, int);
     FilePos     operator+(int, FilePos);
@@ -47,13 +47,13 @@ The class and the various operators can be mapped to Python rather easily
 and intuitively:

     class_<FilePos>("FilePos")
-        .def(self + int())          // __add__
-        .def(int() + self)          // __radd__
-        .def(self - self)           // __sub__
-        .def(self - int())          // __sub__
-        .def(self += int())         // __iadd__
+        .def(self + int())          // __add__
+        .def(int() + self)          // __radd__
+        .def(self - self)           // __sub__
+        .def(self - int())          // __sub__
+        .def(self += int())         // __iadd__
         .def(self -= other<int>())
-        .def(self < self);          // __lt__
+        .def(self < self);          // __lt__
 

The code snippet above is very clear and needs almost no explanation at @@ -69,17 +69,17 @@ similar set of intuitive interfaces can also be used to wrap C++ functions that correspond to these Python special functions. Example:

     class Rational
-    { operator double() const; };
+    { operator double() const; };
 
     Rational pow(Rational, Rational);
     Rational abs(Rational);
     ostream& operator<<(ostream&,Rational);
 
     class_<Rational>()
-        .def(float_(self))                  // __float__
-        .def(pow(self, other<Rational>))    // __pow__
-        .def(abs(self))                     // __abs__
-        .def(str(self))                     // __str__
+        .def(float_(self))                  // __float__
+        .def(pow(self, other<Rational>))    // __pow__
+        .def(abs(self))                     // __abs__
+        .def(str(self))                     // __str__
         ;
 

@@ -100,7 +100,7 @@ Well, the method str requires the operator<< to do its w
-



Num(); float get() const; void set(float value); - ... - }; + ... + };

However, in Python attribute access is fine; it doesn't neccessarily break encapsulation to let users handle attributes directly, because the attributes can just be a different syntax for a method call. Wrapping our Num class using Boost.Python:

- -
+
     class_<Num>("Num")
-        .add_property("rovalue", &Num::get)
-        .add_property("value", &Num::get, &Var::set);
-
-
+ .add_property("rovalue", &Num::get) + .add_property("value", &Num::get, &Num::set); +

And at last, in Python:

     >>> x = Num()
-    >>> x.value = 3.14
+    >>> x.value = 3.14
     >>> x.value, x.rovalue
     (3.14, 3.14)
-    >>> x.rovalue = 2.17 #error!
+    >>> x.rovalue = 2.17 ##error!
 

Take note that the class property rovalue is exposed as read-only since the rovalue setter member function is not passed in:

-    .add_property("rovalue", &Var::get)
+    .add_property("rovalue", &Num::get)
 
@@ -74,7 +72,7 @@ since the rovalue setter member function is not passed in:


-

     struct Base
     {
-        virtual int f() = 0;
-    };
+        virtual int f() = 0;
+    };
 

Since f is a pure virtual function, Base is now an abstract @@ -40,7 +40,7 @@ class. Given an instance of our class, the free function call_f calls some implementation of this virtual function in a concrete derived class:

-    int call_f(Base& b) { return b.f(); }
+    int call_f(Base& b) { return b.f(); }
 

To allow this function to be implemented in a Python derived class, we @@ -49,10 +49,10 @@ need to create a class wrapper:

struct BaseWrap : Base { BaseWrap(PyObject* self_) - : self(self_) {} - int f() { return call_method<int>(self, "f"); } + : self(self_) {} + int f() { return call_method<int>(self, "f"); } PyObject* self; - }; + }; @@ -93,7 +93,7 @@ polymorphically fromC++. Wrapping Base and the free function call_f:

     class_<Base, BaseWrap, boost::noncopyable>("Base", no_init)
-        ;
+        ;
     def("call_f", call_f);
 

@@ -104,31 +104,31 @@ Python. To do that, it needs Base's copy constructor... which isn't available, since Base is an abstract class.

In Python, let us try to instantiate our Base class:

- -
+
     >>> base = Base()
-    RuntimeError: This class cannot be instantiated from Python
-
+ RuntimeError: This class cannot be instantiated from Python +

Why is it an error? Base is an abstract class. As such it is advisable to define the Python wrapper with no_init as we have done above. Doing so will disallow abstract base classes such as Base to be instantiated.

-

Deriving a Python class

-

Now, at last, we can even derive from our base class Base in Python. - Before we can do that, we have to set up our class_ wrapper as:

-
    class_<Base, BaseWrap, boost::noncopyable>("Base")
-        ;
-

Otherwise, we have to suppress the Base class' no_init by adding an - __init__() method to all our derived classes. no_init actually - adds an __init__ method that raises a Python RuntimeError exception.

- -
+

Deriving a Python class

+Now, at last, we can even derive from our base class Base in Python. Before +we can do that, we have to set up our class_ wrapper as:

+
+    class_<Base, BaseWrap, boost::noncopyable>("Base")
+        ;
+
+

+Otherwise, we have to suppress the Base class' no_init by adding an +__init__() method to all our derived classes. no_init actually adds +an __init__ method that raises a Python RuntimeError exception.

+
     >>> class Derived(Base):
-    ...     def f(self):
-    ...         return 42
+    ...     def f(self):
+    ...         return 42
     ...
-
-
+

Cool eh? A Python class deriving from a C++ class!

@@ -159,8 +159,8 @@ declared as pure virtual:

     struct Base
     {
-        virtual int f() { return 0; }
-    };
+        virtual int f() { return 0; }
+    };
 

And instead is implemented to return 0, as shown above.

@@ -168,20 +168,19 @@ And instead is implemented to return 0, as shown above.

struct BaseWrap : Base { BaseWrap(PyObject* self_) - : self(self_) {} - int f() { return call_method<int>(self, "f"); } - static int default_f(Base* b) { return b->Base::f(); } // <<=== added + : self(self_) {} + int f() { return call_method<int>(self, "f"); } + static int default_f(Base* b) { return b->Base::f(); } // <<=== added PyObject* self; - }; + };

then, our Boost.Python wrapper:

- -
    class_<Base, BaseWrap, boost::non_copyable>("Base")
-        .def("f", &BaseWrap::default_f)
-        ;
-
-
+
+    class_<Base, BaseWrap>("Base")
+        .def("f", &BaseWrap::default_f)
+        ;
+

Note that we are allowing Base objects to be instantiated this time, unlike before where we specifically defined the class_<Base> with @@ -190,11 +189,11 @@ unlike before where we specifically defined the class_<Base> with In Python, the results would be as expected:

     >>> base = Base()
-    >>> class Derived(Base):
-    ...     def f(self):
-    ...         return 42
+    >>> class Derived(Base):
+    ...     def f(self):
+    ...         return 42
     ...
-    >>> derived = Derived()
+    >>> derived = Derived()
 

Calling base.f():

@@ -228,7 +227,7 @@ Calling call_f, passing in a derived object:


-

     struct World
     {
-        World(std::string msg): msg(msg) {} // added constructor
-        void set(std::string msg) { this->msg = msg; }
-        std::string greet() { return msg; }
+        World(std::string msg): msg(msg) {} // added constructor
+        void set(std::string msg) { this->msg = msg; }
+        std::string greet() { return msg; }
         std::string msg;
-    };
+    };
 

This time World has no default constructor; our previous @@ -54,12 +54,12 @@ expose instead.

using namespace boost::python; BOOST_PYTHON_MODULE(hello) - { + { class_<World>("World", init<std::string>()) - .def("greet", &World::greet) - .def("set", &World::set) - ; - } + .def("greet", &World::greet) + .def("set", &World::set) + ; + }

init<std::string>() exposes the constructor taking in a @@ -71,10 +71,10 @@ the def() member function. Say for example we have another World constructor taking in two doubles:

     class_<World>("World", init<std::string>())
-        .def(init<double, double>())
-        .def("greet", &World::greet)
-        .def("set", &World::set)
-    ;
+        .def(init<double, double>())
+        .def("greet", &World::greet)
+        .def("set", &World::set)
+    ;
 

On the other hand, if we do not wish to expose any constructors at @@ -93,7 +93,7 @@ Python RuntimeError exception.


-

@@ -29,43 +29,44 @@ Boost.Python wraps (member) function pointers. Unfortunately, C++ function pointers carry no default argument info. Take a function f with default arguments:

-    int f(int, double = 3.14, char const* = "hello");
+    int f(int, double = 3.14, char const* = "hello");
 

But the type of a pointer to the function f has no information about its default arguments:

-    int(*g)(int,double,char const*) = f;    // defaults lost!
+    int(*g)(int,double,char const*) = f;    // defaults lost!
 

When we pass this function pointer to the def function, there is no way to retrieve the default arguments:

-    def("f", f);                            // defaults lost!
+    def("f", f);                            // defaults lost!
 

Because of this, when wrapping C++ code in earlier versions of Boost.Python, we had to resort to writing thin wrappers:

     // write "thin wrappers"
-    int f1(int x) { f(x); }
-    int f2(int x, double y) { f(x,y); }
+    int f1(int x) { f(x); }
+    int f2(int x, double y) { f(x,y); }
 
-    /*...*/
+    /*...*/
 
-        // in module init
-        def("f", f);  // all arguments
-        def("f", f2); // two arguments
-        def("f", f1); // one argument
+        // in module init
+        def("f", f);  // all arguments
+        def("f", f2); // two arguments
+        def("f", f1); // one argument
 

When you want to wrap functions (or member functions) that either:

-
  • have default arguments, or
  • are overloaded with a common sequence of initial arguments

-Boost.Python now has a way to make it easier.

-

-For instance, given a function:

+
  • have default arguments, or
  • are overloaded with a common sequence of initial arguments

BOOST_PYTHON_FUNCTION_OVERLOADS

+Boost.Python now has a way to make it easier. For instance, given a function:

-    int foo(int a, char b = 1, unsigned c = 2, double d = 3);
+    int foo(int a, char b = 1, unsigned c = 2, double d = 3)
+    {
+        /*...*/
+    }
 

The macro invocation:

@@ -73,7 +74,7 @@ The macro invocation:

BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 1, 4)

-Will automatically create the thin wrappers for us. This macro will create +will automatically create the thin wrappers for us. This macro will create a class foo_overloads that can be passed on to def(...). The third and fourth macro argument are the minimum arguments and maximum arguments, respectively. In our foo function the minimum number of arguments is 1 @@ -82,21 +83,58 @@ automatically add all the foo variants for us:

     .def("foo", foo, foo_overloads());
 
+

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS

+Objects here, objects there, objects here there everywhere. More frequently +than anything else, we need to expose member functions of our classes to +Python. Then again, we have the same inconveniences as before when default +arguments or overloads with a common sequence of initial arguments come +into play. Another macro is provided to make this a breeze.

+Like BOOST_PYTHON_FUNCTION_OVERLOADS, +BOOST_PYTHON_FUNCTION_OVERLOADS may be used to automatically create +the thin wrappers for wrapping member functions. Let's have an example:

+
+    struct george
+    {
+        void
+        wack_em(int a, int b = 0, char c = 'x')
+        {
+            /*...*/
+        }
+    };
+
+

+The macro invocation:

+
+    BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(george_overloads, wack_em, 1, 3)
+
+

+will generate a set of thin wrappers for george's wack_em member function +accepting a minimum of 1 and a maximum of 3 arguments (i.e. the third and +fourth macro argument). The thin wrappers are all enclosed in a class named +george_overloads that can then be used as an argument to def(...):

+
+    .def("wack_em", &george::wack_em, george_overloads());
+
+

+See the +overloads reference +for details.

+

init and optional

A similar facility is provided for class constructors, again, with -default arguments or a sequence of overloads. Remember init<...>? For example, +default arguments or a sequence of overloads. Remember init<...>? For example, given a class X with a constructor:

     struct X
     {
         X(int a, char b = 'D', std::string c = "constructor", double d = 0.0);
-        /*...*/
-    }
+        /*...*/
+    }
 

You can easily add this constructor to Boost.Python in one shot:

-    .def(init<int, optional<char, std::string, double> >())
+    .def(init<int, optional<char, std::string, double> >())
 

Notice the use of init<...> and optional<...> to signify the default @@ -105,11 +143,11 @@ Notice the use of init<...> and optional<...> to s - +
-



  • list
  • dict
  • tuple
  • str
  • long_
  • enum

These derived object types act like real Python types. For instance:

-    str(1) ==> "1"
+    str(1) ==> "1"
 

Wherever appropriate, a particular derived object has corresponding @@ -50,11 +50,11 @@ declared below, is wrapped, it will only accept instances of Python's str type and subtypes.

     void f(str name)
-    {
-        object n2 = name.attr("upper")();   // NAME = name.upper()
-        str NAME = name.upper();            // better
+    {
+        object n2 = name.attr("upper")();   // NAME = name.upper()
+        str NAME = name.upper();            // better
         object msg = "%s is bigger than %s" % make_tuple(NAME,name);
-    }
+    }
 

In finer detail:

@@ -76,14 +76,14 @@ of most of Python's mutable types make copies, just as in Python.

Python:

-    >>> d = dict(x.__dict__)     #copies x.__dict__
-    >>> d['whatever']            #modifies the copy
+    >>> d = dict(x.__dict__)     ##copies x.__dict__
+    >>> d['whatever']            ##modifies the copy
 

C++:

-    dict d(x.attr("__dict__"));  #copies x.__dict__
-    d['whatever'] = 3;           #modifies the copy
+    dict d(x.attr("__dict__"));  ##copies x.__dict__
+    d['whatever'] = 3;           ##modifies the copy
 

class_<T> as objects

Due to the dynamic nature of Boost.Python objects, any class_<T> may @@ -92,13 +92,13 @@ also be one of these types! The following code snippet wraps the class

We can use this to create wrapped instances. Example:

-    object vec345 = (
+    object vec345 = (
         class_<Vec2>("Vec2", init<double, double>())
-            .def_readonly("length", &Point::length)
-            .def_readonly("angle", &Point::angle)
-        )(3.0, 4.0);
+            .def_readonly("length", &Point::length)
+            .def_readonly("angle", &Point::angle)
+        )(3.0, 4.0);
 
-    assert(vec345.attr("length") == 5.0);
+    assert(vec345.attr("length") == 5.0);
 
@@ -108,7 +108,7 @@ We can use this to create wrapped instances. Example:


-

the construct:

     enum_<choice>("choice")
-        .value("red", red)
-        .value("blue", blue)
-        ;
+        .value("red", red)
+        .value("blue", blue)
+        ;
 

can be used to expose to Python. The new enum type is created in the @@ -67,16 +67,16 @@ You can access those values in Python as

where my_module is the module where the enum is declared. You can also create a new scope around a class:

-    scope in_X = class_<X>("X")
-                    .def( ... )
-                    .def( ... )
-                ;
+    scope in_X = class_<X>("X")
+                    .def( ... )
+                    .def( ... )
+                ;
 
-    // Expose X::nested as X.nested
+    // Expose X::nested as X.nested
     enum_<X::nested>("nested")
-        .value("red", red)
-        .value("blue", blue)
-        ;
+        .value("red", red)
+        .value("blue", blue)
+        ;
 
@@ -86,7 +86,7 @@ create a new scope around a class:


-

Users may provide custom translation. Here's an example:

-
-    struct PodBayDoorException;
-    void translator(PodBayDoorException const& x) {
+
+    struct PodBayDoorException;
+    void translator(PodBayDoorException const& x) {
         PyErr_SetString(PyExc_UserWarning, "I'm sorry Dave...");
     }
     BOOST_PYTHON_MODULE(kubrick) {
          register_exception_translator<
               PodBayDoorException>(translator);
          ...
-
+
@@ -51,7 +51,7 @@ Users may provide custom translation. Here's an example:


-

     struct World
     {
-        void set(std::string msg) { this->msg = msg; }
-        std::string greet() { return msg; }
+        void set(std::string msg) { this->msg = msg; }
+        std::string greet() { return msg; }
         std::string msg;
-    };
+    };
 

We can expose this to Python by writing a corresponding Boost.Python @@ -44,12 +44,12 @@ C++ Wrapper:

using namespace boost::python; BOOST_PYTHON_MODULE(hello) - { + { class_<World>("World") - .def("greet", &World::greet) - .def("set", &World::set) - ; - } + .def("greet", &World::greet) + .def("set", &World::set) + ; + }

Here, we wrote a C++ class wrapper that exposes the member functions @@ -58,8 +58,8 @@ may use our class World in Python. Here's a sample Python session:

     >>> import hello
     >>> planet = hello.World()
-    >>> planet.set('howdy')
-    >>> planet.greet()
+    >>> planet.set('howdy')
+    >>> planet.greet()
     'howdy'
 
@@ -70,7 +70,7 @@ may use our class World in Python. Here's a sample Python session:


-

-    double x = o.attr("length"); // compile error
+    double x = o.attr("length"); // compile error
 

In the code above, we got a compiler error because Boost.Python @@ -52,15 +52,15 @@ appropriate exception is thrown. To avoid an exception, we need to test for extractibility:

     extract<Vec2&> x(o);
-    if (x.check()) {
-        Vec2& v = x(); ...
+    if (x.check()) {
+        Vec2& v = x(); ...
 

The astute reader might have noticed that the extract<T> facility in fact solves the mutable copying problem:

     dict d = extract<dict>(x.attr("__dict__"));
-    d['whatever'] = 3;          #modifies x.__dict__ !
+    d['whatever'] = 3;          ##modifies x.__dict__ !
 
@@ -70,7 +70,7 @@ facility in fact solves the mutable copying problem:


-



Consider this trivial inheritance structure:

-    struct Base { virtual ~Base(); };
+    struct Base { virtual ~Base(); };
     struct Derived : Base {};
 

@@ -42,22 +42,22 @@ instances:

     void b(Base*);
     void d(Derived*);
-    Base* factory() { return new Derived; }
+    Base* factory() { return new Derived; }
 

We've seen how we can wrap the base class Base:

     class_<Base>("Base")
-        /*...*/
-        ;
+        /*...*/
+        ;
 

Now we can inform Boost.Python of the inheritance relationship between Derived and its base class Base. Thus:

-    class_<Derived, bases<Base> >("Derived")
-        /*...*/
-        ;
+    class_<Derived, bases<Base> >("Derived")
+        /*...*/
+        ;
 

Doing so, we get some things for free:

@@ -89,7 +89,7 @@ call policies later.


-

  • 1 category (forward)
  • 1 operation category (next())
  • Raises StopIteration exception at end

The typical Python iteration protocol: for y in x... is as follows:

-    iter = x.__iter__()         #get iterator
+    iter = x.__iter__()         ##get iterator
     try:
         while 1:
-        y = iter.next()         #get each item
-        ...                     #process y
-    except StopIteration: pass  #iterator exhausted
+        y = iter.next()         ##get each item
+        ...                     ##process y
+    except StopIteration: pass  ##iterator exhausted
 

Boost.Python provides some mechanisms to make C++ iterators play along @@ -47,14 +47,14 @@ nicely as Python iterators. What we need to do is to produce appropriate __iter__ function from C++ iterators that is compatible with the Python iteration protocol. For example:

-    object get_iterator = iterator<vector<int> >();
+    object get_iterator = iterator<vector<int> >();
     object iter = get_iterator(v);
     object first = iter.next();
 

Or for use in class_<>:

-    .def("__iter__", iterator<vector<int> >())
+    .def("__iter__", iterator<vector<int> >())
 

range

@@ -81,8 +81,8 @@ bogon Particle accelerator code:

Now, our C++ Wrapper:

     class_<F>("Field")
-        .property("pions", range(&F::p_begin, &F::p_end))
-        .property("bogons", range(&F::b_begin, &F::b_end));
+        .property("pions", range(&F::p_begin, &F::p_end))
+        .property("bogons", range(&F::b_begin, &F::b_end));
 
@@ -92,7 +92,7 @@ Now, our C++ Wrapper:


-

- +

-

+It was mentioned in passing in the previous section that +BOOST_PYTHON_FUNCTION_OVERLOADS and BOOST_PYTHON_FUNCTION_OVERLOADS +can also be used for overloaded functions and member functions with a +common sequence of initial arguments. Here is an example:

+
+     void foo()
+     {
+        /*...*/
+     }
+
+     void foo(bool a)
+     {
+        /*...*/
+     }
+
+     void foo(bool a, int b)
+     {
+        /*...*/
+     }
+
+     void foo(bool a, int b, char c)
+     {
+        /*...*/
+     }
+
+

+Like in the previous section, we can generate thin wrappers for these +overloaded functions in one-shot:

+
+    BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 0, 3)
+
+

+Then...

+
+    .def("foo", foo, foo_overloads());
+
+

+Notice though that we have a situation now where we have a minimum of zero +(0) arguments and a maximum of 3 arguments.

+

Manual Wrapping

+It is important to emphasize however that the overloaded functions must +have a common sequence of initial arguments. Otherwise, our scheme above +will not work.

+

+The following illustrates an alternate scheme for manually wrapping an +overloaded member function instead of +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS. Obviously, the same technique +can be applied to wrapping overloaded non- member functions.

+

+We have here our C++ classes:

+
+    struct X
+    {
+        bool f(int a, double b = 0, char c = 'x')
+        {
+            return true;
+        }
+
+        int f(int a, int b, int c)
+        {
+            return a + b + c;
+        };
+    };
+
+

+Notice that class X has two overloaded functions with different signatures. +The types of the arguments, and the return are totally different, unlike +above where we have a common sequence of initial arguments.

+

+We shall start by introducing some member function pointer variables:

+
+    bool    (X::*fx1)(int)              = &X::f;
+    bool    (X::*fx2)(int, double)      = &X::f;
+    bool    (X::*fx3)(int, double, char)= &X::f;
+    int     (X::*fx4)(int, int, int)    = &X::f;
+
+

+The first three member function pointers take care of the first X::f +overload. The one with default arguments. The last member function pointer +takes care of the second X::f overload.

+

+With these in hand, we can proceed to define and wrap this for Python:

+
+    .def("f", fx1)
+    .def("f", fx2)
+    .def("f", fx3)
+    .def("f", fx4)
+
+

+Actually, we can mix and match manual wrapping of overloaded functions and +automatic wrapping through BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS and +its sister, BOOST_PYTHON_FUNCTION_OVERLOADS. Since the first overload +has default arguments, we can use BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS +to automatically wrap the first three of the defs above and manually +wrap just the last. Here's how we'll do this:

+
+    BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(xf_overloads, f, 1, 4)
+
+

+Create a member function pointers as above for both X::f overloads:

+
+    bool    (X::*fx1)(int, double, char)    = &X::f;
+    int     (X::*fx2)(int, int, int)        = &X::f;
+
+

+Then...

+
+    .def("f", fx1, xf_overloads());
+    .def("f", fx2)
+
+ + + + + + +
+
+
+ + diff --git a/doc/tutorial/doc/quickstart.html b/doc/tutorial/doc/quickstart.html index ec1a89ac..02ba7a1a 100644 --- a/doc/tutorial/doc/quickstart.html +++ b/doc/tutorial/doc/quickstart.html @@ -39,9 +39,9 @@ Following C/C++ tradition, let's start with the "hello, world". A C++ Function:

     char const* greet()
-    {
+    {
        return "hello, world";
-    }
+    }
 

can be exposed to Python by writing a Boost.Python wrapper:

@@ -50,9 +50,9 @@ can be exposed to Python by writing a Boost.Python wrapper:

using namespace boost::python; BOOST_PYTHON_MODULE(hello) - { + { def("greet", greet); - } + }

That's it. We're done. We can now build this as a shared library. The @@ -70,7 +70,7 @@ resulting DLL is now visible to Python. Here's a sample Python session:


-