mirror of
https://github.com/boostorg/python.git
synced 2026-01-19 16:32:16 +00:00
607 lines
42 KiB
HTML
607 lines
42 KiB
HTML
<!-- Copyright David Abrahams 2006. Distributed under the Boost -->
|
||
<!-- Software License, Version 1.0. (See accompanying -->
|
||
<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
|
||
<html>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||
<title>Functions</title>
|
||
<link rel="stylesheet" href="../boostbook.css" type="text/css">
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.66.1">
|
||
<link rel="start" href="../index.html" title="Chapter 1. python 1.0">
|
||
<link rel="up" href="../index.html" title="Chapter 1. python 1.0">
|
||
<link rel="prev" href="exposing.html" title=" Exposing Classes">
|
||
<link rel="next" href="object.html" title=" Object Interface">
|
||
</head>
|
||
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
||
<table cellpadding="2" width="100%">
|
||
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td>
|
||
<td align="center"><a href="../../../../../../../index.htm">Home</a></td>
|
||
<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td>
|
||
<td align="center"><a href="../../../../../../../people/people.htm">People</a></td>
|
||
<td align="center"><a href="../../../../../../../more/faq.htm">FAQ</a></td>
|
||
<td align="center"><a href="../../../../../../../more/index.htm">More</a></td>
|
||
</table>
|
||
<hr>
|
||
<div class="spirit-nav">
|
||
<a accesskey="p" href="exposing.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="object.html"><img src="../images/next.png" alt="Next"></a>
|
||
</div>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
|
||
<a name="python.functions"></a>Functions</h2></div></div></div>
|
||
<div class="toc"><dl>
|
||
<dt><span class="section"><a href="functions.html#python.call_policies">Call Policies</a></span></dt>
|
||
<dt><span class="section"><a href="functions.html#python.overloading">Overloading</a></span></dt>
|
||
<dt><span class="section"><a href="functions.html#python.default_arguments">Default Arguments</a></span></dt>
|
||
<dt><span class="section"><a href="functions.html#python.auto_overloading">Auto-Overloading</a></span></dt>
|
||
</dl></div>
|
||
<p>
|
||
In this chapter, we'll look at Boost.Python powered functions in closer detail.
|
||
We shall see some facilities to make exposing C++ functions to Python safe
|
||
from potential pifalls such as dangling pointers and references. We shall also
|
||
see facilities that will make it even easier for us to expose C++ functions
|
||
that take advantage of C++ features such as overloading and default arguments.
|
||
</p>
|
||
<div class="blockquote"><blockquote class="blockquote"><p>
|
||
<span class="emphasis"><em>Read on...</em></span>
|
||
</p></blockquote></div>
|
||
<p>
|
||
But before you do, you might want to fire up Python 2.2 or later and type
|
||
<tt class="literal">>>> import this</tt>.
|
||
</p>
|
||
<pre class="programlisting">>>> import this
|
||
The Zen of Python, by Tim Peters
|
||
Beautiful is better than ugly.
|
||
Explicit is better than implicit.
|
||
Simple is better than complex.
|
||
Complex is better than complicated.
|
||
Flat is better than nested.
|
||
Sparse is better than dense.
|
||
Readability counts.
|
||
Special cases aren't special enough to break the rules.
|
||
Although practicality beats purity.
|
||
Errors should never pass silently.
|
||
Unless explicitly silenced.
|
||
In the face of ambiguity, refuse the temptation to guess.
|
||
There should be one-- and preferably only one --obvious way to do it
|
||
Although that way may not be obvious at first unless you're Dutch.
|
||
Now is better than never.
|
||
Although never is often better than <span class="bold"><b>right</b></span> now.
|
||
If the implementation is hard to explain, it's a bad idea.
|
||
If the implementation is easy to explain, it may be a good idea.
|
||
Namespaces are one honking great idea -- let's do more of those!
|
||
</pre>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="python.call_policies"></a>Call Policies</h3></div></div></div>
|
||
<p>
|
||
In C++, we often deal with arguments and return types such as pointers and
|
||
references. Such primitive types are rather, ummmm, low level and they really
|
||
don't tell us much. At the very least, we don't know the owner of the pointer
|
||
or the referenced object. No wonder languages such as Java and Python never
|
||
deal with such low level entities. In C++, it's usually considered a good
|
||
practice to use smart pointers which exactly describe ownership semantics.
|
||
Still, even good C++ interfaces use raw references and pointers sometimes,
|
||
so Boost.Python must deal with them. To do this, it may need your help. Consider
|
||
the following C++ function:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">X</span><span class="special">&</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&</span> <span class="identifier">y</span><span class="special">,</span> <span class="identifier">Z</span><span class="special">*</span> <span class="identifier">z</span><span class="special">);</span>
|
||
</pre>
|
||
<p>
|
||
How should the library wrap this function? A naive approach builds a Python
|
||
X object around result reference. This strategy might or might not work out.
|
||
Here's an example where it didn't
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">>>></span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span> <span class="identifier">z</span><span class="special">)</span> # <span class="identifier">x</span> <span class="identifier">refers</span> <span class="identifier">to</span> <span class="identifier">some</span> <span class="identifier">C</span><span class="special">++</span> <span class="identifier">X</span>
|
||
<span class="special">>>></span> <span class="identifier">del</span> <span class="identifier">y</span>
|
||
<span class="special">>>></span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">some_method</span><span class="special">()</span> # <span class="identifier">CRASH</span><span class="special">!</span>
|
||
</pre>
|
||
<p>
|
||
What's the problem?
|
||
</p>
|
||
<p>
|
||
Well, what if f() was implemented as shown below:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">X</span><span class="special">&</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&</span> <span class="identifier">y</span><span class="special">,</span> <span class="identifier">Z</span><span class="special">*</span> <span class="identifier">z</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">y</span><span class="special">.</span><span class="identifier">z</span> <span class="special">=</span> <span class="identifier">z</span><span class="special">;</span>
|
||
<span class="keyword">return</span> <span class="identifier">y</span><span class="special">.</span><span class="identifier">x</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
The problem is that the lifetime of result X& is tied to the lifetime
|
||
of y, because the f() returns a reference to a member of the y object. This
|
||
idiom is is not uncommon and perfectly acceptable in the context of C++.
|
||
However, Python users should not be able to crash the system just by using
|
||
our C++ interface. In this case deleting y will invalidate the reference
|
||
to X. We have a dangling reference.
|
||
</p>
|
||
<p>
|
||
Here's what's happening:
|
||
</p>
|
||
<div class="orderedlist"><ol type="1">
|
||
<li>
|
||
<tt class="literal">f</tt> is called passing in a reference to <tt class="literal">y</tt>
|
||
and a pointer to <tt class="literal">z</tt>
|
||
</li>
|
||
<li>
|
||
A reference to <tt class="literal">y.x</tt> is returned
|
||
</li>
|
||
<li>
|
||
<tt class="literal">y</tt> is deleted. <tt class="literal">x</tt> is a dangling reference
|
||
</li>
|
||
<li>
|
||
<tt class="literal">x.some_method()</tt> is called
|
||
</li>
|
||
<li><span class="bold"><b>BOOM!</b></span></li>
|
||
</ol></div>
|
||
<p>
|
||
We could copy result into a new object:
|
||
</p>
|
||
<p>
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">>>></span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span> <span class="identifier">z</span><span class="special">).</span><span class="identifier">set</span><span class="special">(</span><span class="number">42</span><span class="special">)</span> <span class="comment"># Result disappears
|
||
</span><span class="special">>>></span> <span class="identifier">y</span><span class="special">.</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">get</span><span class="special">()</span> <span class="comment"># No crash, but still bad
|
||
</span><span class="number">3.14</span>
|
||
</pre>
|
||
<p>
|
||
This is not really our intent of our C++ interface. We've broken our promise
|
||
that the Python interface should reflect the C++ interface as closely as
|
||
possible.
|
||
</p>
|
||
<p>
|
||
Our problems do not end there. Suppose Y is implemented as follows:
|
||
</p>
|
||
<p>
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">struct</span> <span class="identifier">Y</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">X</span> <span class="identifier">x</span><span class="special">;</span> <span class="identifier">Z</span><span class="special">*</span> <span class="identifier">z</span><span class="special">;</span>
|
||
<span class="keyword">int</span> <span class="identifier">z_value</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">z</span><span class="special">-></span><span class="identifier">value</span><span class="special">();</span> <span class="special">}</span>
|
||
<span class="special">};</span>
|
||
</pre>
|
||
<p>
|
||
Notice that the data member <tt class="literal">z</tt> is held by class Y using
|
||
a raw pointer. Now we have a potential dangling pointer problem inside Y:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">>>></span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span> <span class="identifier">z</span><span class="special">)</span> # <span class="identifier">y</span> <span class="identifier">refers</span> <span class="identifier">to</span> <span class="identifier">z</span>
|
||
<span class="special">>>></span> <span class="identifier">del</span> <span class="identifier">z</span> # <span class="identifier">Kill</span> <span class="identifier">the</span> <span class="identifier">z</span> <span class="identifier">object</span>
|
||
<span class="special">>>></span> <span class="identifier">y</span><span class="special">.</span><span class="identifier">z_value</span><span class="special">()</span> # <span class="identifier">CRASH</span><span class="special">!</span>
|
||
</pre>
|
||
<p>
|
||
For reference, here's the implementation of <tt class="literal">f</tt> again:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">X</span><span class="special">&</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&</span> <span class="identifier">y</span><span class="special">,</span> <span class="identifier">Z</span><span class="special">*</span> <span class="identifier">z</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">y</span><span class="special">.</span><span class="identifier">z</span> <span class="special">=</span> <span class="identifier">z</span><span class="special">;</span>
|
||
<span class="keyword">return</span> <span class="identifier">y</span><span class="special">.</span><span class="identifier">x</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
Here's what's happening:
|
||
</p>
|
||
<div class="orderedlist"><ol type="1">
|
||
<li>
|
||
<tt class="literal">f</tt> is called passing in a reference to <tt class="literal">y</tt>
|
||
and a pointer to <tt class="literal">z</tt>
|
||
</li>
|
||
<li>
|
||
A pointer to <tt class="literal">z</tt> is held by <tt class="literal">y</tt>
|
||
</li>
|
||
<li>
|
||
A reference to <tt class="literal">y.x</tt> is returned
|
||
</li>
|
||
<li>
|
||
<tt class="literal">z</tt> is deleted. <tt class="literal">y.z</tt> is a dangling pointer
|
||
</li>
|
||
<li>
|
||
<tt class="literal">y.z_value()</tt> is called
|
||
</li>
|
||
<li>
|
||
<tt class="literal">z->value()</tt> is called
|
||
</li>
|
||
<li><span class="bold"><b>BOOM!</b></span></li>
|
||
</ol></div>
|
||
<a name="call_policies.call_policies"></a><h2>
|
||
<a name="id455614"></a>
|
||
Call Policies
|
||
</h2>
|
||
<p>
|
||
Call Policies may be used in situations such as the example detailed above.
|
||
In our example, <tt class="literal">return_internal_reference</tt> and <tt class="literal">with_custodian_and_ward</tt>
|
||
are our friends:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f</span><span class="special">,</span>
|
||
<span class="identifier">return_internal_reference</span><span class="special"><</span><span class="number">1</span><span class="special">,</span>
|
||
<span class="identifier">with_custodian_and_ward</span><span class="special"><</span><span class="number">1</span><span class="special">,</span> <span class="number">2</span><span class="special">></span> <span class="special">>());</span>
|
||
</pre>
|
||
<p>
|
||
What are the <tt class="literal">1</tt> and <tt class="literal">2</tt> parameters, you
|
||
ask?
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">return_internal_reference</span><span class="special"><</span><span class="number">1</span>
|
||
</pre>
|
||
<p>
|
||
Informs Boost.Python that the first argument, in our case <tt class="literal">Y&
|
||
y</tt>, is the owner of the returned reference: <tt class="literal">X&</tt>.
|
||
The "<tt class="literal">1</tt>" simply specifies the first argument.
|
||
In short: "return an internal reference <tt class="literal">X&</tt> owned
|
||
by the 1st argument <tt class="literal">Y& y</tt>".
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">with_custodian_and_ward</span><span class="special"><</span><span class="number">1</span><span class="special">,</span> <span class="number">2</span><span class="special">></span>
|
||
</pre>
|
||
<p>
|
||
Informs Boost.Python that the lifetime of the argument indicated by ward
|
||
(i.e. the 2nd argument: <tt class="literal">Z* z</tt>) is dependent on the lifetime
|
||
of the argument indicated by custodian (i.e. the 1st argument: <tt class="literal">Y&
|
||
y</tt>).
|
||
</p>
|
||
<p>
|
||
It is also important to note that we have defined two policies above. Two
|
||
or more policies can be composed by chaining. Here's the general syntax:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">policy1</span><span class="special"><</span><span class="identifier">args</span><span class="special">...,</span>
|
||
<span class="identifier">policy2</span><span class="special"><</span><span class="identifier">args</span><span class="special">...,</span>
|
||
<span class="identifier">policy3</span><span class="special"><</span><span class="identifier">args</span><span class="special">...></span> <span class="special">></span> <span class="special">></span>
|
||
</pre>
|
||
<p>
|
||
Here is the list of predefined call policies. A complete reference detailing
|
||
these can be found <a href="../../../../v2/reference.html#models_of_call_policies" target="_top">here</a>.
|
||
</p>
|
||
<div class="itemizedlist"><ul type="disc">
|
||
<li>
|
||
<span class="bold"><b>with_custodian_and_ward</b></span><br> Ties lifetimes
|
||
of the arguments
|
||
</li>
|
||
<li>
|
||
<span class="bold"><b>with_custodian_and_ward_postcall</b></span><br>
|
||
Ties lifetimes of the arguments and results
|
||
</li>
|
||
<li>
|
||
<span class="bold"><b>return_internal_reference</b></span><br> Ties lifetime
|
||
of one argument to that of result
|
||
</li>
|
||
<li>
|
||
<span class="bold"><b>return_value_policy<T> with T one of:</b></span><br>
|
||
</li>
|
||
<li>
|
||
<span class="bold"><b>reference_existing_object</b></span><br> naive
|
||
(dangerous) approach
|
||
</li>
|
||
<li>
|
||
<span class="bold"><b>copy_const_reference</b></span><br> Boost.Python
|
||
v1 approach
|
||
</li>
|
||
<li>
|
||
<span class="bold"><b>copy_non_const_reference</b></span><br>
|
||
</li>
|
||
<li>
|
||
<span class="bold"><b>manage_new_object</b></span><br> Adopt a pointer
|
||
and hold the instance
|
||
</li>
|
||
</ul></div>
|
||
<p class="blurb">
|
||
<span class="inlinemediaobject"><img src="../images/smiley.png" alt="smiley"></span> <span class="bold"><b>Remember the Zen, Luke:</b></span><br>
|
||
<br> "Explicit is better than implicit"<br> "In the face
|
||
of ambiguity, refuse the temptation to guess"<br>
|
||
</p>
|
||
</div>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="python.overloading"></a>Overloading</h3></div></div></div>
|
||
<p>
|
||
The following illustrates a scheme for manually wrapping an overloaded member
|
||
functions. Of course, the same technique can be applied to wrapping overloaded
|
||
non-member functions.
|
||
</p>
|
||
<p>
|
||
We have here our C++ class:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">struct</span> <span class="identifier">X</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">bool</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="keyword">bool</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">b</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="keyword">bool</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">b</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">c</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="keyword">int</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">b</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">c</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">return</span> <span class="identifier">a</span> <span class="special">+</span> <span class="identifier">b</span> <span class="special">+</span> <span class="identifier">c</span><span class="special">;</span>
|
||
<span class="special">};</span>
|
||
<span class="special">};</span>
|
||
</pre>
|
||
<p>
|
||
Class X has 4 overloaded functions. We shall start by introducing some member
|
||
function pointer variables:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">bool</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx1</span><span class="special">)(</span><span class="keyword">int</span><span class="special">)</span> <span class="special">=</span> <span class="special">&</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span>
|
||
<span class="keyword">bool</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx2</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">double</span><span class="special">)</span> <span class="special">=</span> <span class="special">&</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span>
|
||
<span class="keyword">bool</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx3</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">char</span><span class="special">)=</span> <span class="special">&</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span>
|
||
<span class="keyword">int</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx4</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">)</span> <span class="special">=</span> <span class="special">&</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span>
|
||
</pre>
|
||
<p>
|
||
With these in hand, we can proceed to define and wrap this for Python:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx1</span><span class="special">)</span>
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx2</span><span class="special">)</span>
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx3</span><span class="special">)</span>
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx4</span><span class="special">)</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="python.default_arguments"></a>Default Arguments</h3></div></div></div>
|
||
<p>
|
||
Boost.Python wraps (member) function pointers. Unfortunately, C++ function
|
||
pointers carry no default argument info. Take a function <tt class="literal">f</tt>
|
||
with default arguments:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">int</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">double</span> <span class="special">=</span> <span class="number">3.14</span><span class="special">,</span> <span class="keyword">char</span> <span class="keyword">const</span><span class="special">*</span> <span class="special">=</span> <span class="string">"hello"</span><span class="special">);</span>
|
||
</pre>
|
||
<p>
|
||
But the type of a pointer to the function <tt class="literal">f</tt> has no information
|
||
about its default arguments:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">int</span><span class="special">(*</span><span class="identifier">g</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword">double</span><span class="special">,</span><span class="keyword">char</span> <span class="keyword">const</span><span class="special">*)</span> <span class="special">=</span> <span class="identifier">f</span><span class="special">;</span> <span class="comment">// defaults lost!
|
||
</span></pre>
|
||
<p>
|
||
When we pass this function pointer to the <tt class="literal">def</tt> function,
|
||
there is no way to retrieve the default arguments:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f</span><span class="special">);</span> <span class="comment">// defaults lost!
|
||
</span></pre>
|
||
<p>
|
||
Because of this, when wrapping C++ code, we had to resort to manual wrapping
|
||
as outlined in the <a href="functions.html#python.overloading" title="Overloading">previous section</a>,
|
||
or writing thin wrappers:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="comment">// write "thin wrappers"
|
||
</span><span class="keyword">int</span> <span class="identifier">f1</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">x</span><span class="special">)</span> <span class="special">{</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span> <span class="special">}</span>
|
||
<span class="keyword">int</span> <span class="identifier">f2</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">{</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">);</span> <span class="special">}</span>
|
||
|
||
<span class="comment">/*...*/</span>
|
||
|
||
<span class="comment">// in module init
|
||
</span> <span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f</span><span class="special">);</span> <span class="comment">// all arguments
|
||
</span> <span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f2</span><span class="special">);</span> <span class="comment">// two arguments
|
||
</span> <span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f1</span><span class="special">);</span> <span class="comment">// one argument
|
||
</span></pre>
|
||
<p>
|
||
When you want to wrap functions (or member functions) that either:
|
||
</p>
|
||
<div class="itemizedlist"><ul type="disc">
|
||
<li>
|
||
have default arguments, or
|
||
</li>
|
||
<li>
|
||
are overloaded with a common sequence of initial arguments
|
||
</li>
|
||
</ul></div>
|
||
<a name="default_arguments.boost_python_function_overloads"></a><h2>
|
||
<a name="id457647"></a>
|
||
BOOST_PYTHON_FUNCTION_OVERLOADS
|
||
</h2>
|
||
<p>
|
||
Boost.Python now has a way to make it easier. For instance, given a function:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">int</span> <span class="identifier">foo</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">b</span> <span class="special">=</span> <span class="number">1</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="identifier">c</span> <span class="special">=</span> <span class="number">2</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d</span> <span class="special">=</span> <span class="number">3</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="comment">/*...*/</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
The macro invocation:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">foo_overloads</span><span class="special">,</span> <span class="identifier">foo</span><span class="special">,</span> <span class="number">1</span><span class="special">,</span> <span class="number">4</span><span class="special">)</span>
|
||
</pre>
|
||
<p>
|
||
will automatically create the thin wrappers for us. This macro will create
|
||
a class <tt class="literal">foo_overloads</tt> that can be passed on to <tt class="literal">def(...)</tt>.
|
||
The third and fourth macro argument are the minimum arguments and maximum
|
||
arguments, respectively. In our <tt class="literal">foo</tt> function the minimum
|
||
number of arguments is 1 and the maximum number of arguments is 4. The <tt class="literal">def(...)</tt>
|
||
function will automatically add all the foo variants for us:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">def</span><span class="special">(</span><span class="string">"foo"</span><span class="special">,</span> <span class="identifier">foo</span><span class="special">,</span> <span class="identifier">foo_overloads</span><span class="special">());</span>
|
||
</pre>
|
||
<a name="default_arguments.boost_python_member_function_overloads"></a><h2>
|
||
<a name="id457963"></a>
|
||
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS
|
||
</h2>
|
||
<p>
|
||
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.
|
||
</p>
|
||
<p>
|
||
Like <tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt>, <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt>
|
||
may be used to automatically create the thin wrappers for wrapping member
|
||
functions. Let's have an example:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">struct</span> <span class="identifier">george</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">void</span>
|
||
<span class="identifier">wack_em</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">b</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">c</span> <span class="special">=</span> <span class="char">'x'</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="comment">/*...*/</span>
|
||
<span class="special">}</span>
|
||
<span class="special">};</span>
|
||
</pre>
|
||
<p>
|
||
The macro invocation:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">george_overloads</span><span class="special">,</span> <span class="identifier">wack_em</span><span class="special">,</span> <span class="number">1</span><span class="special">,</span> <span class="number">3</span><span class="special">)</span>
|
||
</pre>
|
||
<p>
|
||
will generate a set of thin wrappers for george's <tt class="literal">wack_em</tt>
|
||
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 <tt class="literal">george_overloads</tt> that can then be used
|
||
as an argument to <tt class="literal">def(...)</tt>:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"wack_em"</span><span class="special">,</span> <span class="special">&</span><span class="identifier">george</span><span class="special">::</span><span class="identifier">wack_em</span><span class="special">,</span> <span class="identifier">george_overloads</span><span class="special">());</span>
|
||
</pre>
|
||
<p>
|
||
See the <a href="../../../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec" target="_top">overloads
|
||
reference</a> for details.
|
||
</p>
|
||
<a name="default_arguments.init_and_optional"></a><h2>
|
||
<a name="id458323"></a>
|
||
init and optional
|
||
</h2>
|
||
<p>
|
||
A similar facility is provided for class constructors, again, with default
|
||
arguments or a sequence of overloads. Remember <tt class="literal">init<...></tt>?
|
||
For example, given a class X with a constructor:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">struct</span> <span class="identifier">X</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">X</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">b</span> <span class="special">=</span> <span class="char">'D'</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">c</span> <span class="special">=</span> <span class="string">"constructor"</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d</span> <span class="special">=</span> <span class="number">0.0</span><span class="special">);</span>
|
||
<span class="comment">/*...*/</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
You can easily add this constructor to Boost.Python in one shot:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special"><</span><span class="keyword">int</span><span class="special">,</span> <span class="identifier">optional</span><span class="special"><</span><span class="keyword">char</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">,</span> <span class="keyword">double</span><span class="special">></span> <span class="special">>())</span>
|
||
</pre>
|
||
<p>
|
||
Notice the use of <tt class="literal">init<...></tt> and <tt class="literal">optional<...></tt>
|
||
to signify the default (optional arguments).
|
||
</p>
|
||
</div>
|
||
<div class="section" lang="en">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="python.auto_overloading"></a>Auto-Overloading</h3></div></div></div>
|
||
<p>
|
||
It was mentioned in passing in the previous section that <tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt>
|
||
and <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> can also be
|
||
used for overloaded functions and member functions with a common sequence
|
||
of initial arguments. Here is an example:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">void</span> <span class="identifier">foo</span><span class="special">()</span>
|
||
<span class="special">{</span>
|
||
<span class="comment">/*...*/</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="keyword">void</span> <span class="identifier">foo</span><span class="special">(</span><span class="keyword">bool</span> <span class="identifier">a</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="comment">/*...*/</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="keyword">void</span> <span class="identifier">foo</span><span class="special">(</span><span class="keyword">bool</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">b</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="comment">/*...*/</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="keyword">void</span> <span class="identifier">foo</span><span class="special">(</span><span class="keyword">bool</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">b</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">c</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="comment">/*...*/</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
Like in the previous section, we can generate thin wrappers for these overloaded
|
||
functions in one-shot:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">foo_overloads</span><span class="special">,</span> <span class="identifier">foo</span><span class="special">,</span> <span class="number">0</span><span class="special">,</span> <span class="number">3</span><span class="special">)</span>
|
||
</pre>
|
||
<p>
|
||
Then...
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"foo"</span><span class="special">,</span> <span class="special">(</span><span class="keyword">void</span><span class="special">(*)(</span><span class="keyword">bool</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">char</span><span class="special">))</span><span class="number">0</span><span class="special">,</span> <span class="identifier">foo_overloads</span><span class="special">());</span>
|
||
</pre>
|
||
<p>
|
||
Notice though that we have a situation now where we have a minimum of zero
|
||
(0) arguments and a maximum of 3 arguments.
|
||
</p>
|
||
<a name="auto_overloading.manual_wrapping"></a><h2>
|
||
<a name="id459095"></a>
|
||
Manual Wrapping
|
||
</h2>
|
||
<p>
|
||
It is important to emphasize however that <span class="bold"><b>the overloaded
|
||
functions must have a common sequence of initial arguments</b></span>. Otherwise,
|
||
our scheme above will not work. If this is not the case, we have to wrap
|
||
our functions <a href="functions.html#python.overloading" title="Overloading">manually</a>.
|
||
</p>
|
||
<p>
|
||
Actually, we can mix and match manual wrapping of overloaded functions and
|
||
automatic wrapping through <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt>
|
||
and its sister, <tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt>. Following
|
||
up on our example presented in the section <a href="functions.html#python.overloading" title="Overloading">on
|
||
overloading</a>, since the first 4 overload functins have a common sequence
|
||
of initial arguments, we can use <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt>
|
||
to automatically wrap the first three of the <tt class="literal">def</tt>s and
|
||
manually wrap just the last. Here's how we'll do this:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="identifier">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">xf_overloads</span><span class="special">,</span> <span class="identifier">f</span><span class="special">,</span> <span class="number">1</span><span class="special">,</span> <span class="number">4</span><span class="special">)</span>
|
||
</pre>
|
||
<p>
|
||
Create a member function pointers as above for both X::f overloads:
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="keyword">bool</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx1</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">char</span><span class="special">)</span> <span class="special">=</span> <span class="special">&</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span>
|
||
<span class="keyword">int</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx2</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">)</span> <span class="special">=</span> <span class="special">&</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span>
|
||
</pre>
|
||
<p>
|
||
Then...
|
||
</p>
|
||
<pre class="programlisting">
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx1</span><span class="special">,</span> <span class="identifier">xf_overloads</span><span class="special">());</span>
|
||
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx2</span><span class="special">)</span>
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
|
||
<td align="left"></td>
|
||
<td align="right"><small>Copyright © 2002-2005 Joel
|
||
de Guzman, David Abrahams</small></td>
|
||
</tr></table>
|
||
<hr>
|
||
<div class="spirit-nav">
|
||
<a accesskey="p" href="exposing.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="object.html"><img src="../images/next.png" alt="Next"></a>
|
||
</div>
|
||
</body>
|
||
</html>
|