diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
commit | 1a78a62555be32868418fe52f8e330c9d0f95d5a (patch) | |
tree | d3765a80e7d3b9640ec2e930743630cd6b9fce2b /doc/html/signals/tutorial.html | |
download | boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.gz boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.bz2 boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.zip |
Imported Upstream version 1.49.0upstream/1.49.0
Diffstat (limited to 'doc/html/signals/tutorial.html')
-rwxr-xr-x | doc/html/signals/tutorial.html | 1151 |
1 files changed, 1151 insertions, 0 deletions
diff --git a/doc/html/signals/tutorial.html b/doc/html/signals/tutorial.html new file mode 100755 index 0000000000..e9541782ba --- /dev/null +++ b/doc/html/signals/tutorial.html @@ -0,0 +1,1151 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Tutorial</title> +<link rel="stylesheet" href="../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset"> +<link rel="up" href="../signals.html" title="Chapter 24. Boost.Signals"> +<link rel="prev" href="../signals.html" title="Chapter 24. Boost.Signals"> +<link rel="next" href="reference.html" title="Reference"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../boost.png"></td> +<td align="center"><a href="../../../index.html">Home</a></td> +<td align="center"><a href="../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="../signals.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../signals.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="reference.html"><img src="../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="signals.tutorial"></a>Tutorial</h2></div></div></div> +<div class="toc"><dl> +<dt><span class="section"><a href="tutorial.html#id3136968">How to Read this Tutorial</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3137031">Compatibility Note</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3137144">Hello, World! (Beginner)</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3137299">Calling multiple slots</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3137713">Passing values to and from slots</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3138628">Connection Management</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3139402">Example: Document-View</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3139530">Linking against the Signals library</a></span></dt> +</dl></div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="id3136968"></a>How to Read this Tutorial</h3></div></div></div> +<p>This tutorial is not meant to be read linearly. Its top-level +structure roughly separates different concepts in the library +(e.g., handling calling multiple slots, passing values to and from +slots) and in each of these concepts the basic ideas are presented +first and then more complex uses of the library are described +later. Each of the sections is marked <span class="emphasis"><em>Beginner</em></span>, +<span class="emphasis"><em>Intermediate</em></span>, or <span class="emphasis"><em>Advanced</em></span> to help guide the +reader. The <span class="emphasis"><em>Beginner</em></span> sections include information that all +library users should know; one can make good use of the Signals +library after having read only the <span class="emphasis"><em>Beginner</em></span> sections. The +<span class="emphasis"><em>Intermediate</em></span> sections build on the <span class="emphasis"><em>Beginner</em></span> +sections with slightly more complex uses of the library. Finally, +the <span class="emphasis"><em>Advanced</em></span> sections detail very advanced uses of the +Signals library, that often require a solid working knowledge of +the <span class="emphasis"><em>Beginner</em></span> and <span class="emphasis"><em>Intermediate</em></span> topics; most users +will not need to read the <span class="emphasis"><em>Advanced</em></span> sections.</p> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="id3137031"></a>Compatibility Note</h3></div></div></div> +<p>Boost.Signals has two syntactical forms: the preferred form and +the compatibility form. The preferred form fits more closely with the +C++ language and reduces the number of separate template parameters +that need to be considered, often improving readability; however, the +preferred form is not supported on all platforms due to compiler +bugs. The compatible form will work on all compilers supported by +Boost.Signals. Consult the table below to determine which syntactic +form to use for your compiler. Users of Boost.Function, please note +that the preferred syntactic form in Signals is equivalent to that of +Function's preferred syntactic form.</p> +<p>If your compiler does not appear in this list, please try the +preferred syntax and report your results to the Boost list so that +we can keep this table up-to-date.</p> +<div class="informaltable"><table class="table"> +<colgroup> +<col> +<col> +</colgroup> +<thead><tr> +<th align="left">Preferred syntax</th> +<th align="left">Portable syntax</th> +</tr></thead> +<tbody><tr> +<td align="left"> + <div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"><p>GNU C++ 2.95.x, 3.0.x, 3.1.x</p></li> +<li class="listitem"><p>Comeau C++ 4.2.45.2</p></li> +<li class="listitem"><p>SGI MIPSpro 7.3.0</p></li> +<li class="listitem"><p>Intel C++ 5.0, 6.0</p></li> +<li class="listitem"><p>Compaq's cxx 6.2</p></li> +<li class="listitem"><p>Microsoft Visual C++ 7.1</p></li> +</ul></div> + </td> +<td align="left"> + <div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"><p><span class="emphasis"><em>Any compiler supporting the preferred syntax</em></span></p></li> +<li class="listitem"><p>Microsoft Visual C++ 6.0, 7.0</p></li> +<li class="listitem"><p>Borland C++ 5.5.1</p></li> +<li class="listitem"><p>Sun WorkShop 6 update 2 C++ 5.3</p></li> +<li class="listitem"><p>Metrowerks CodeWarrior 8.1</p></li> +</ul></div> + </td> +</tr></tbody> +</table></div> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="id3137144"></a>Hello, World! (Beginner)</h3></div></div></div> +<p>The following example writes "Hello, World!" using signals and +slots. First, we create a signal <code class="computeroutput">sig</code>, a signal that +takes no arguments and has a void return value. Next, we connect +the <code class="computeroutput">hello</code> function object to the signal using the +<code class="computeroutput">connect</code> method. Finally, use the signal +<code class="computeroutput">sig</code> like a function to call the slots, which in turns +invokes <code class="computeroutput">HelloWorld::operator()</code> to print "Hello, +World!".</p> +<div class="informaltable"><table class="table"> +<colgroup> +<col> +<col> +</colgroup> +<thead><tr> +<th align="left">Preferred syntax</th> +<th align="left">Portable syntax</th> +</tr></thead> +<tbody><tr> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +struct HelloWorld +{ + void operator()() const + { + std::cout << "Hello, World!" << std::endl; + } +}; + +// ... + +// Signal with no arguments and a void return value +<code class="computeroutput"><a class="link" href="../boost/signal.html" title="Class template signal">boost::signal</a></code><void ()> sig; + +// Connect a HelloWorld slot +HelloWorld hello; +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(hello); + +// Call all of the slots +sig(); +</pre> +</td> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +struct HelloWorld +{ + void operator()() const + { + std::cout << "Hello, World!" << std::endl; + } +}; + +// ... + +// Signal with no arguments and a void return value +<code class="computeroutput"><a class="link" href="../boost/signalN.html" title="Class template signalN">boost::signal0</a></code><void> sig; + +// Connect a HelloWorld slot +HelloWorld hello; +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(hello); + +// Call all of the slots +sig(); +</pre> +</td> +</tr></tbody> +</table></div> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="id3137299"></a>Calling multiple slots</h3></div></div></div> +<div class="toc"><dl> +<dt><span class="section"><a href="tutorial.html#id3137304">Connecting multiple slots (Beginner)</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3137489">Ordering slot call groups (Intermediate)</a></span></dt> +</dl></div> +<div class="section"> +<div class="titlepage"><div><div><h4 class="title"> +<a name="id3137304"></a>Connecting multiple slots (Beginner)</h4></div></div></div> +<p>Calling a single slot from a signal isn't very interesting, so +we can make the Hello, World program more interesting by splitting +the work of printing "Hello, World!" into two completely separate +slots. The first slot will print "Hello" and may look like +this:</p> +<pre class="programlisting"> +struct Hello +{ + void operator()() const + { + std::cout << "Hello"; + } +}; +</pre> +<p>The second slot will print ", World!" and a newline, to complete +the program. The second slot may look like this:</p> +<pre class="programlisting"> +struct World +{ + void operator()() const + { + std::cout << ", World!" << std::endl; + } +}; +</pre> +<p>Like in our previous example, we can create a signal +<code class="computeroutput">sig</code> that takes no arguments and has a +<code class="computeroutput">void</code> return value. This time, we connect both a +<code class="computeroutput">hello</code> and a <code class="computeroutput">world</code> slot to the same +signal, and when we call the signal both slots will be called.</p> +<div class="informaltable"><table class="table"> +<colgroup> +<col> +<col> +</colgroup> +<thead><tr> +<th align="left">Preferred syntax</th> +<th align="left">Portable syntax</th> +</tr></thead> +<tbody><tr> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +<code class="computeroutput"><a class="link" href="../boost/signal.html" title="Class template signal">boost::signal</a></code><void ()> sig; + +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(Hello()); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(World()); + +sig(); +</pre> +</td> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +<code class="computeroutput"><a class="link" href="../boost/signalN.html" title="Class template signalN">boost::signal0</a></code><void> sig; + +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(Hello()); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(World()); + +sig(); +</pre> +</td> +</tr></tbody> +</table></div> +<p>By default, slots are called in first-in first-out (FIFO) order, +so the output of this program will be as expected:</p> +<pre class="programlisting"> +Hello, World! +</pre> +</div> +<div class="section"> +<div class="titlepage"><div><div><h4 class="title"> +<a name="id3137489"></a>Ordering slot call groups (Intermediate)</h4></div></div></div> +<p>Slots are free to have side effects, and that can mean that some +slots will have to be called before others even if they are not connected in that order. The Boost.Signals +library allows slots to be placed into groups that are ordered in +some way. For our Hello, World program, we want "Hello" to be +printed before ", World!", so we put "Hello" into a group that must +be executed before the group that ", World!" is in. To do this, we +can supply an extra parameter at the beginning of the +<code class="computeroutput">connect</code> call that specifies the group. Group values +are, by default, <code class="computeroutput">int</code>s, and are ordered by the integer +< relation. Here's how we construct Hello, World:</p> +<div class="informaltable"><table class="table"> +<colgroup> +<col> +<col> +</colgroup> +<thead><tr> +<th align="left">Preferred syntax</th> +<th align="left">Portable syntax</th> +</tr></thead> +<tbody><tr> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +<code class="computeroutput"><a class="link" href="../boost/signal.html" title="Class template signal">boost::signal</a></code><void ()> sig; +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(1, World()); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(0, Hello()); +sig(); +</pre> +</td> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +<code class="computeroutput"><a class="link" href="../boost/signalN.html" title="Class template signalN">boost::signal0</a></code><void> sig; +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(1, World()); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(0, Hello()); +sig(); +</pre> +</td> +</tr></tbody> +</table></div> +<p>This program will correctly print "Hello, World!", because the +<code class="computeroutput">Hello</code> object is in group 0, which precedes group 1 where +the <code class="computeroutput">World</code> object resides. The group +parameter is, in fact, optional. We omitted it in the first Hello, +World example because it was unnecessary when all of the slots are +independent. So what happens if we mix calls to connect that use the +group parameter and those that don't? The "unnamed" slots (i.e., those +that have been connected without specifying a group name) can be +placed at the front or back of the slot list (by passing +<code class="computeroutput">boost::signals::at_front</code> or <code class="computeroutput">boost::signals::at_back</code> +as the last parameter to <code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>, respectively), and defaults to the end of the list. When +a group is specified, the final parameter describes where the slot +will be placed within the group ordering. If we add a new slot +to our example like this:</p> +<pre class="programlisting"> +struct GoodMorning +{ + void operator()() const + { + std::cout << "... and good morning!" << std::endl; + } +}; + +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(GoodMorning()); +</pre> +<p>... we will get the result we wanted:</p> +<pre class="programlisting"> +Hello, World! +... and good morning! +</pre> +</div> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="id3137713"></a>Passing values to and from slots</h3></div></div></div> +<div class="toc"><dl> +<dt><span class="section"><a href="tutorial.html#id3137718">Slot Arguments (Beginner)</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3137963">Signal Return Values (Advanced)</a></span></dt> +</dl></div> +<div class="section"> +<div class="titlepage"><div><div><h4 class="title"> +<a name="id3137718"></a>Slot Arguments (Beginner)</h4></div></div></div> +<p>Signals can propagate arguments to each of the slots they call. +For instance, a signal that propagates mouse motion events might +want to pass along the new mouse coordinates and whether the mouse +buttons are pressed.</p> +<p>As an example, we'll create a signal that passes two +<code class="computeroutput">float</code> arguments to its slots. Then we'll create a few +slots that print the results of various arithmetic operations on +these values.</p> +<pre class="programlisting"> +void print_sum(float x, float y) +{ + std::cout << "The sum is " << x+y << std::endl; +} + +void print_product(float x, float y) +{ + std::cout << "The product is " << x*y << std::endl; +} + +void print_difference(float x, float y) +{ + std::cout << "The difference is " << x-y << std::endl; +} + +void print_quotient(float x, float y) +{ + std::cout << "The quotient is " << x/y << std::endl; +} +</pre> +<div class="informaltable"><table class="table"> +<colgroup> +<col> +<col> +</colgroup> +<thead><tr> +<th align="left">Preferred syntax</th> +<th align="left">Portable syntax</th> +</tr></thead> +<tbody><tr> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +<code class="computeroutput"><a class="link" href="../boost/signal.html" title="Class template signal">boost::signal</a></code><void (float, float)> sig; + +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&print_sum); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&print_product); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&print_difference); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&print_quotient); + +sig(5, 3); +</pre> +</td> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +<code class="computeroutput"><a class="link" href="../boost/signalN.html" title="Class template signalN">boost::signal2</a></code><void, float, float> sig; + +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&print_sum); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&print_product); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&print_difference); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&print_quotient); + +sig(5, 3); +</pre> +</td> +</tr></tbody> +</table></div> +<p>This program will print out the following:</p> +<pre class="programlisting"> +The sum is 8 +The product is 15 +The difference is 2 +The quotient is 1.66667 +</pre> +<p>So any values that are given to <code class="computeroutput">sig</code> when it is +called like a function are passed to each of the slots. We have to +declare the types of these values up front when we create the +signal. The type <code class="computeroutput"><a class="link" href="../boost/signal.html" title="Class template signal">boost::signal</a><void (float, +float)></code> means that the signal has a <code class="computeroutput">void</code> +return value and takes two <code class="computeroutput">float</code> values. Any slot +connected to <code class="computeroutput">sig</code> must therefore be able to take two +<code class="computeroutput">float</code> values.</p> +</div> +<div class="section"> +<div class="titlepage"><div><div><h4 class="title"> +<a name="id3137963"></a>Signal Return Values (Advanced)</h4></div></div></div> +<p>Just as slots can receive arguments, they can also return +values. These values can then be returned back to the caller of the +signal through a <em class="firstterm">combiner</em>. The combiner is a mechanism +that can take the results of calling slots (there many be no +results or a hundred; we don't know until the program runs) and +coalesces them into a single result to be returned to the caller. +The single result is often a simple function of the results of the +slot calls: the result of the last slot call, the maximum value +returned by any slot, or a container of all of the results are some +possibilities.</p> +<p>We can modify our previous arithmetic operations example +slightly so that the slots all return the results of computing the +product, quotient, sum, or difference. Then the signal itself can +return a value based on these results to be printed:</p> +<div class="informaltable"><table class="table"> +<colgroup> +<col> +<col> +</colgroup> +<thead><tr> +<th align="left">Preferred syntax</th> +<th align="left">Portable syntax</th> +</tr></thead> +<tbody><tr> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +float product(float x, float y) { return x*y; } +float quotient(float x, float y) { return x/y; } +float sum(float x, float y) { return x+y; } +float difference(float x, float y) { return x-y; } + +<code class="computeroutput"><a class="link" href="../boost/signal.html" title="Class template signal">boost::signal</a></code><float (float x, float y)> sig; + +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&product); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&quotient); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&sum); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&difference); + +std::cout << sig(5, 3) << std::endl; +</pre> +</td> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +float product(float x, float y) { return x*y; } +float quotient(float x, float y) { return x/y; } +float sum(float x, float y) { return x+y; } +float difference(float x, float y) { return x-y; } + +<code class="computeroutput"><a class="link" href="../boost/signalN.html" title="Class template signalN">boost::signal2</a></code><float, float, float> sig; + +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&product); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&quotient); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&sum); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&difference); + +std::cout << sig(5, 3) << std::endl; +</pre> +</td> +</tr></tbody> +</table></div> +<p>This example program will output <code class="computeroutput">2</code>. This is because the +default behavior of a signal that has a return type +(<code class="computeroutput">float</code>, the first template argument given to the +<code class="computeroutput"><a class="link" href="../boost/signal.html" title="Class template signal">boost::signal</a></code> class template) is to call all slots and +then return the result returned by the last slot called. This +behavior is admittedly silly for this example, because slots have +no side effects and the result is the last slot connect.</p> +<p>A more interesting signal result would be the maximum of the +values returned by any slot. To do this, we create a custom +combiner that looks like this:</p> +<pre class="programlisting"> +template<typename T> +struct maximum +{ + typedef T result_type; + + template<typename InputIterator> + T operator()(InputIterator first, InputIterator last) const + { + // If there are no slots to call, just return the + // default-constructed value + if (first == last) + return T(); + + T max_value = *first++; + while (first != last) { + if (max_value < *first) + max_value = *first; + ++first; + } + + return max_value; + } +}; +</pre> +<p>The <code class="computeroutput">maximum</code> class template acts as a function +object. Its result type is given by its template parameter, and +this is the type it expects to be computing the maximum based on +(e.g., <code class="computeroutput">maximum<float></code> would find the maximum +<code class="computeroutput">float</code> in a sequence of <code class="computeroutput">float</code>s). When a +<code class="computeroutput">maximum</code> object is invoked, it is given an input +iterator sequence <code class="computeroutput">[first, last)</code> that includes the +results of calling all of the slots. <code class="computeroutput">maximum</code> uses this +input iterator sequence to calculate the maximum element, and +returns that maximum value.</p> +<p>We actually use this new function object type by installing it +as a combiner for our signal. The combiner template argument +follows the signal's calling signature:</p> +<div class="informaltable"><table class="table"> +<colgroup> +<col> +<col> +</colgroup> +<thead><tr> +<th align="left">Preferred syntax</th> +<th align="left">Portable syntax</th> +</tr></thead> +<tbody><tr> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +<code class="computeroutput"><a class="link" href="../boost/signal.html" title="Class template signal">boost::signal</a></code><float (float x, float y), + maximum<float> > sig; +</pre> +</td> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +<code class="computeroutput"><a class="link" href="../boost/signalN.html" title="Class template signalN">boost::signal2</a></code><float, float, float, + maximum<float> > sig; +</pre> +</td> +</tr></tbody> +</table></div> +<p>Now we can connect slots that perform arithmetic functions and +use the signal:</p> +<pre class="programlisting"> +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&quotient); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&product); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&sum); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&difference); + +std::cout << sig(5, 3) << std::endl; +</pre> +<p>The output of this program will be <code class="computeroutput">15</code>, because +regardless of the order in which the slots are connected, the product +of 5 and 3 will be larger than the quotient, sum, or +difference.</p> +<p>In other cases we might want to return all of the values +computed by the slots together, in one large data structure. This +is easily done with a different combiner:</p> +<pre class="programlisting"> +template<typename Container> +struct aggregate_values +{ + typedef Container result_type; + + template<typename InputIterator> + Container operator()(InputIterator first, InputIterator last) const + { + return Container(first, last); + } +}; +</pre> +<p> +Again, we can create a signal with this new combiner: +</p> +<div class="informaltable"><table class="table"> +<colgroup> +<col> +<col> +</colgroup> +<thead><tr> +<th align="left">Preferred syntax</th> +<th align="left">Portable syntax</th> +</tr></thead> +<tbody><tr> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +<code class="computeroutput"><a class="link" href="../boost/signal.html" title="Class template signal">boost::signal</a></code><float (float, float), + aggregate_values<std::vector<float> > > sig; + +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&quotient); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&product); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&sum); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&difference); + +std::vector<float> results = sig(5, 3); +std::copy(results.begin(), results.end(), + std::ostream_iterator<float>(cout, " ")); +</pre> +</td> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +<code class="computeroutput"><a class="link" href="../boost/signalN.html" title="Class template signalN">boost::signal2</a></code><float, float, float, + aggregate_values<std::vector<float> > > sig; + +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&quotient); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&product); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&sum); +sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(&difference); + +std::vector<float> results = sig(5, 3); +std::copy(results.begin(), results.end(), + std::ostream_iterator<float>(cout, " ")); +</pre> +</td> +</tr></tbody> +</table></div> +<p>The output of this program will contain 15, 8, 1.6667, and 2. It +is interesting here that +the first template argument for the <code class="computeroutput">signal</code> class, +<code class="computeroutput">float</code>, is not actually the return type of the signal. +Instead, it is the return type used by the connected slots and will +also be the <code class="computeroutput">value_type</code> of the input iterators passed +to the combiner. The combiner itself is a function object and its +<code class="computeroutput">result_type</code> member type becomes the return type of the +signal.</p> +<p>The input iterators passed to the combiner transform dereference +operations into slot calls. Combiners therefore have the option to +invoke only some slots until some particular criterion is met. For +instance, in a distributed computing system, the combiner may ask +each remote system whether it will handle the request. Only one +remote system needs to handle a particular request, so after a +remote system accepts the work we do not want to ask any other +remote systems to perform the same task. Such a combiner need only +check the value returned when dereferencing the iterator, and +return when the value is acceptable. The following combiner returns +the first non-NULL pointer to a <code class="computeroutput">FulfilledRequest</code> data +structure, without asking any later slots to fulfill the +request:</p> +<pre class="programlisting"> +struct DistributeRequest { + typedef FulfilledRequest* result_type; + + template<typename InputIterator> + result_type operator()(InputIterator first, InputIterator last) const + { + while (first != last) { + if (result_type fulfilled = *first) + return fulfilled; + ++first; + } + return 0; + } +}; +</pre> +</div> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="id3138628"></a>Connection Management</h3></div></div></div> +<div class="toc"><dl> +<dt><span class="section"><a href="tutorial.html#id3138632">Disconnecting Slots (Beginner)</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3138755">Blocking Slots (Beginner)</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3138834">Scoped connections (Intermediate)</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3138884">Disconnecting equivalent slots (Intermediate)</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3138969">Automatic connection management (Intermediate)</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3139173">When can disconnections occur? (Intermediate)</a></span></dt> +<dt><span class="section"><a href="tutorial.html#id3139243">Passing slots (Intermediate)</a></span></dt> +</dl></div> +<div class="section"> +<div class="titlepage"><div><div><h4 class="title"> +<a name="id3138632"></a>Disconnecting Slots (Beginner)</h4></div></div></div> +<p>Slots aren't expected to exist indefinately after they are +connected. Often slots are only used to receive a few events and +are then disconnected, and the programmer needs control to decide +when a slot should no longer be connected.</p> +<p>The entry point for managing connections explicitly is the +<code class="computeroutput"><a class="link" href="../boost/signals/connection.html" title="Class connection">boost::signals::connection</a></code> class. The +<code class="computeroutput"><a class="link" href="../boost/signals/connection.html" title="Class connection">connection</a></code> class uniquely represents the connection +between a particular signal and a particular slot. The +<code class="computeroutput"><a class="link" href="../boost/signals/connection.html#id804447-bb">connected</a>()</code> method checks if the signal and slot are +still connected, and the <code class="computeroutput"><a class="link" href="../boost/signals/connection.html#id804411-bb">disconnect()</a></code> method +disconnects the signal and slot if they are connected before it is +called. Each call to the signal's <code class="computeroutput">connect()</code> method +returns a connection object, which can be used to determine if the +connection still exists or to disconnect the signal and slot.</p> +<pre class="programlisting"> +boost::signals::connection c = sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(HelloWorld()); +if (c.<code class="computeroutput">connected</code>()) { +<span class="emphasis"><em>// c is still connected to the signal</em></span> + sig(); <span class="emphasis"><em>// Prints "Hello, World!"</em></span> +} + +c.disconnect(); <span class="emphasis"><em>// Disconnect the HelloWorld object</em></span> +assert(!c.<code class="computeroutput">connected</code>()); <span class="emphasis"><em>c isn't connected any more</em></span> + +sig(); <span class="emphasis"><em>// Does nothing: there are no connected slots</em></span> +</pre> +</div> +<div class="section"> +<div class="titlepage"><div><div><h4 class="title"> +<a name="id3138755"></a>Blocking Slots (Beginner)</h4></div></div></div> +<p>Slots can be temporarily "blocked", meaning that they will be +ignored when the signal is invoked but have not been disconnected. The +<code class="computeroutput">block</code> member function +temporarily blocks a slot, which can be unblocked via +<code class="computeroutput">unblock</code>. Here is an example of +blocking/unblocking slots:</p> +<pre class="programlisting"> +boost::signals::connection c = sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(HelloWorld()); +sig(); <span class="emphasis"><em>// Prints "Hello, World!"</em></span> + +c.<code class="computeroutput">block</code>(); <span class="emphasis"><em>// block the slot</em></span> +assert(c.<code class="computeroutput">blocked</code>()); +sig(); <span class="emphasis"><em>// No output: the slot is blocked</em></span> + +c.<code class="computeroutput">unblock</code>(); <span class="emphasis"><em>// unblock the slot</em></span> +sig(); <span class="emphasis"><em>// Prints "Hello, World!"</em></span> +</pre> +</div> +<div class="section"> +<div class="titlepage"><div><div><h4 class="title"> +<a name="id3138834"></a>Scoped connections (Intermediate)</h4></div></div></div> +<p>The <code class="computeroutput">boost::signals::scoped_connection</code> class +references a signal/slot connection that will be disconnected when +the <code class="computeroutput">scoped_connection</code> class goes out of scope. This +ability is useful when a connection need only be temporary, +e.g.,</p> +<pre class="programlisting"> +{ + boost::signals::scoped_connection c = sig.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(ShortLived()); + sig(); <span class="emphasis"><em>// will call ShortLived function object</em></span> +} +sig(); <span class="emphasis"><em>// ShortLived function object no longer connected to sig</em></span> +</pre> +</div> +<div class="section"> +<div class="titlepage"><div><div><h4 class="title"> +<a name="id3138884"></a>Disconnecting equivalent slots (Intermediate)</h4></div></div></div> +<p>One can disconnect slots that are equivalent to a given function +object using a form of the +<code class="computeroutput"><a class="link" href="../boost/signalN.html#id824916-bb">disconnect</a></code> method, so long as +the type of the function object has an accessible <code class="computeroutput">==</code> +operator. For instance: + +</p> +<div class="informaltable"><table class="table"> +<colgroup> +<col> +<col> +</colgroup> +<thead><tr> +<th align="left">Preferred syntax</th> +<th align="left">Portable syntax</th> +</tr></thead> +<tbody><tr> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +void foo(); +void bar(); + +signal<void()> sig; + +sig.connect(&foo); +sig.connect(&bar); + +// disconnects foo, but not bar +sig.disconnect(&foo); +</pre> +</td> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +void foo(); +void bar(); + +signal0<void> sig; + +sig.connect(&foo); +sig.connect(&bar); + +// disconnects foo, but not bar +sig.disconnect(&foo); +</pre> +</td> +</tr></tbody> +</table></div> +</div> +<div class="section"> +<div class="titlepage"><div><div><h4 class="title"> +<a name="id3138969"></a>Automatic connection management (Intermediate)</h4></div></div></div> +<p>Boost.Signals can automatically track the lifetime of objects +involved in signal/slot connections, including automatic +disconnection of slots when objects involved in the slot call are +destroyed. For instance, consider a simple news delivery service, +where clients connect to a news provider that then sends news to +all connected clients as information arrives. The news delivery +service may be constructed like this: </p> +<div class="informaltable"><table class="table"> +<colgroup> +<col> +<col> +</colgroup> +<thead><tr> +<th align="left">Preferred syntax</th> +<th align="left">Portable syntax</th> +</tr></thead> +<tbody><tr> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +class NewsItem { /* ... */ }; + +boost::signal<void (const NewsItem&)> deliverNews; +</pre> +</td> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +class NewsItem { /* ... */ }; + +boost::signal1<void, const NewsItem&> deliverNews; +</pre> +</td> +</tr></tbody> +</table></div> +<p>Clients that wish to receive news updates need only connect a +function object that can receive news items to the +<code class="computeroutput">deliverNews</code> signal. For instance, we may have a +special message area in our application specifically for news, +e.g.,:</p> +<pre class="programlisting"> +struct NewsMessageArea : public MessageArea +{ +public: + // ... + + void displayNews(const NewsItem& news) const + { + messageText = news.text(); + update(); + } +}; + +// ... +NewsMessageArea newsMessageArea = new NewsMessageArea(/* ... */); +// ... +deliverNews.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(boost::bind(&NewsMessageArea::displayNews, + newsMessageArea, _1)); +</pre> +<p>However, what if the user closes the news message area, +destroying the <code class="computeroutput">newsMessageArea</code> object that +<code class="computeroutput">deliverNews</code> knows about? Most likely, a segmentation +fault will occur. However, with Boost.Signals one need only make +<code class="computeroutput">NewsMessageArea</code> <span class="emphasis"><em>trackable</em></span>, and the slot +involving <code class="computeroutput">newsMessageArea</code> will be disconnected when +<code class="computeroutput">newsMessageArea</code> is destroyed. The +<code class="computeroutput">NewsMessageArea</code> class is made trackable by deriving +publicly from the <code class="computeroutput">boost::signals::trackable</code> class, +e.g.:</p> +<pre class="programlisting"> +struct NewsMessageArea : public MessageArea, public boost::signals::trackable +{ + // ... +}; +</pre> +<p>At this time there is a significant limitation to the use of +<code class="computeroutput">trackable</code> objects in making slot connections: function +objects built using Boost.Bind are understood, such that pointers +or references to <code class="computeroutput">trackable</code> objects passed to +<code class="computeroutput">boost::bind</code> will be found and tracked.</p> +<p><span class="bold"><strong>Warning</strong></span>: User-defined function objects and function +objects from other libraries (e.g., Boost.Function or Boost.Lambda) +do not implement the required interfaces for <code class="computeroutput">trackable</code> +object detection, and <span class="emphasis"><em>will silently ignore any bound trackable +objects</em></span>. Future versions of the Boost libraries will address +this limitation.</p> +</div> +<div class="section"> +<div class="titlepage"><div><div><h4 class="title"> +<a name="id3139173"></a>When can disconnections occur? (Intermediate)</h4></div></div></div> +<p>Signal/slot disconnections occur when any of these conditions +occur:</p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"><p>The connection is explicitly disconnected via the connection's +<code class="computeroutput">disconnect</code> method directly, or indirectly via the +signal's <code class="computeroutput">disconnect</code> method or +<code class="computeroutput">scoped_connection</code>'s destructor.</p></li> +<li class="listitem"><p>A <code class="computeroutput">trackable</code> object bound to the slot is +destroyed.</p></li> +<li class="listitem"><p>The signal is destroyed.</p></li> +</ul></div> +<p>These events can occur at any time without disrupting a signal's +calling sequence. If a signal/slot connection is disconnected at +any time during a signal's calling sequence, the calling sequence +will still continue but will not invoke the disconnected slot. +Additionally, a signal may be destroyed while it is in a calling +sequence, and which case it will complete its slot call sequence +but may not be accessed directly.</p> +<p>Signals may be invoked recursively (e.g., a signal A calls a +slot B that invokes signal A...). The disconnection behavior does +not change in the recursive case, except that the slot calling +sequence includes slot calls for all nested invocations of the +signal.</p> +</div> +<div class="section"> +<div class="titlepage"><div><div><h4 class="title"> +<a name="id3139243"></a>Passing slots (Intermediate)</h4></div></div></div> +<p>Slots in the Boost.Signals library are created from arbitrary +function objects, and therefore have no fixed type. However, it is +commonplace to require that slots be passed through interfaces that +cannot be templates. Slots can be passed via the +<code class="computeroutput">slot_type</code> for each particular signal type and any +function object compatible with the signature of the signal can be +passed to a <code class="computeroutput">slot_type</code> parameter. For instance:</p> +<div class="informaltable"><table class="table"> +<colgroup> +<col> +<col> +</colgroup> +<thead><tr> +<th align="left">Preferred syntax</th> +<th align="left">Portable syntax</th> +</tr></thead> +<tbody><tr> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +class Button +{ + typedef boost::signal<void (int x, int y)> OnClick; + +public: + void doOnClick(const OnClick::slot_type& slot); + +private: + OnClick onClick; +}; + +void Button::doOnClick( + const OnClick::slot_type& slot + ) +{ + onClick.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(slot); +} + +void printCoordinates(long x, long y) +{ + std::cout << "(" << x << ", " << y << ")\n"; +} + +void f(Button& button) +{ + button.doOnClick(&printCoordinates); +} +</pre> +</td> +<td align="left"> +<pre xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" class="table-programlisting"> +class Button +{ + typedef <code class="computeroutput"><a class="link" href="../boost/signalN.html" title="Class template signalN">boost::signal2</a></code><void,int,int> OnClick; + +public: + void doOnClick(const OnClick::slot_type& slot); + +private: + OnClick onClick; +}; + +void Button::doOnClick( + const OnClick::slot_type& slot + ) +{ + onClick.<code class="computeroutput"><a class="link" href="../boost/signalN.html#id1292363-bb">connect</a></code>(slot); +} + +void printCoordinates(long x, long y) +{ + std::cout << "(" << x << ", " << y << ")\n"; +} + +void f(Button& button) +{ + button.doOnClick(&printCoordinates); +} +</pre> +</td> +</tr></tbody> +</table></div> +<p>The <code class="computeroutput">doOnClick</code> method is now functionally equivalent +to the <code class="computeroutput">connect</code> method of the <code class="computeroutput">onClick</code> +signal, but the details of the <code class="computeroutput">doOnClick</code> method can be +hidden in an implementation detail file.</p> +</div> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="id3139402"></a>Example: Document-View</h3></div></div></div> +<p>Signals can be used to implement flexible Document-View + architectures. The document will contain a signal to which each of + the views can connect. The following <code class="computeroutput">Document</code> class + defines a simple text document that supports mulitple views. Note + that it stores a single signal to which all of the views will be + connected.</p> +<pre class="programlisting">class Document +{ +public: + typedef boost::signal<void (bool)> signal_t; + typedef boost::signals::connection connection_t; + +public: + Document() + {} + + connection_t connect(signal_t::slot_function_type subscriber) + { + return m_sig.connect(subscriber); + } + + void disconnect(connection_t subscriber) + { + subscriber.disconnect(); + } + + void append(const char* s) + { + m_text += s; + m_sig(true); + } + + const std::string& getText() const + { + return m_text; + } + +private: + signal_t m_sig; + std::string m_text; +};</pre> +<p>Next, we can define a <code class="computeroutput">View</code> base class from which + views can derive. This isn't strictly required, but it keeps the + Document-View logic separate from the logic itself. Note that the + constructor just connects the view to the document and the + destructor disconnects the view.</p> +<pre class="programlisting"> +class View +{ +public: + View(Document& m) + : m_document(m) + { + m_connection = m_document.connect(boost::bind(&View::refresh, this, _1)); + } + + virtual ~View() + { + m_document.disconnect(m_connection); + } + + virtual void refresh(bool bExtended) const = 0; + +protected: + Document& m_document; + +private: + Document::connection_t m_connection; +}; + </pre> +<p>Finally, we can begin to define views. The + following <code class="computeroutput">TextView</code> class provides a simple view of the + document text.</p> +<pre class="programlisting">class TextView : public View +{ +public: + TextView(Document& doc) + : View(doc) + {} + + virtual void refresh(bool bExtended) const + { + std::cout << "TextView: " << m_document.getText() << std::endl; + } +};</pre> +<p>Alternatively, we can provide a view of the document + translated into hex values using the <code class="computeroutput">HexView</code> + view:</p> +<pre class="programlisting">class HexView : public View +{ +public: + HexView(Document& doc) + : View(doc) + {} + + virtual void refresh(bool bExtended) const + { + const std::string& s = m_document.getText(); + + std::cout << "HexView:"; + + for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) + std::cout << ' ' << std::hex << static_cast<int>(*it); + + std::cout << std::endl; + } +};</pre> +<p>To tie the example together, here is a + simple <code class="computeroutput">main</code> function that sets up two views and then + modifies the document:</p> +<pre class="programlisting">int main(int argc, char* argv[]) +{ + Document doc; + TextView v1(doc); + HexView v2(doc); + + doc.append(argc == 2 ? argv[1] : "Hello world!"); + return 0; +}</pre> +<p>The complete example source, contributed by Keith MacDonald, + is available in <a href="../../../libs/signals/example/doc_view.cpp" target="_top"><code class="computeroutput">libs/signals/example/doc_view.cpp</code></a>.</p> +</div> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="id3139530"></a>Linking against the Signals library</h3></div></div></div> +<p>Part of the Boost.Signals library is compiled into a binary + library that must be linked into your application to use + Signals. Please refer to + the <a href="../../../more/getting_started.html" target="_top">Getting Started</a> + guide. You will need to link against the <code class="computeroutput">boost_signals</code> + library.</p> +</div> +</div> +<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> +<td align="left"><p><small>Last revised: January 29, 2007 at 20:05:29 +0000</small></p></td> +<td align="right"><div class="copyright-footer">Copyright © 2001-2004 Douglas Gregor<p>Use, modification and distribution is subject to the Boost + Software License, Version 1.0. (See accompanying file + <code class="filename">LICENSE_1_0.txt</code> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)</p> +</div></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="../signals.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../signals.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="reference.html"><img src="../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> |