• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<?xml version="1.0" encoding="utf-8"?>
2<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
3  "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
4<!--
5Copyright Douglas Gregor 2001-2004
6Copyright Frank Mori Hess 2007-2009
7
8Distributed under the Boost Software License, Version 1.0. (See accompanying
9file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10-->
11<section last-revision="$Date: 2007-06-12 14:01:23 -0400 (Tue, 12 Jun 2007) $" id="signals2.tutorial">
12  <title>Tutorial</title>
13
14  <using-namespace name="boost::signals2"/>
15  <using-namespace name="boost"/>
16  <using-class name="boost::signals2::signal"/>
17  <using-class name="boost::signals2::slot"/>
18
19  <section>
20    <title>How to Read this Tutorial</title>
21<para>This tutorial is not meant to be read linearly. Its top-level
22structure roughly separates different concepts in the library
23(e.g., handling calling multiple slots, passing values to and from
24slots) and in each of these concepts the basic ideas are presented
25first and then more complex uses of the library are described
26later. Each of the sections is marked <emphasis>Beginner</emphasis>,
27<emphasis>Intermediate</emphasis>, or <emphasis>Advanced</emphasis> to help guide the
28reader. The <emphasis>Beginner</emphasis> sections include information that all
29library users should know; one can make good use of the Signals2
30library after having read only the <emphasis>Beginner</emphasis> sections. The
31<emphasis>Intermediate</emphasis> sections build on the <emphasis>Beginner</emphasis>
32sections with slightly more complex uses of the library. Finally,
33the <emphasis>Advanced</emphasis> sections detail very advanced uses of the
34Signals2 library, that often require a solid working knowledge of
35the <emphasis>Beginner</emphasis> and <emphasis>Intermediate</emphasis> topics; most users
36will not need to read the <emphasis>Advanced</emphasis> sections.</para>
37</section>
38
39<section><title>Hello, World! (Beginner)</title>
40<para>The following example writes "Hello, World!" using signals and
41slots. First, we create a signal <code>sig</code>, a signal that
42takes no arguments and has a void return value. Next, we connect
43the <code>hello</code> function object to the signal using the
44<code>connect</code> method. Finally, use the signal
45<code>sig</code> like a function to call the slots, which in turns
46invokes <code>HelloWorld::operator()</code> to print "Hello,
47World!".</para>
48<programlisting><xi:include href="hello_world_def_code_snippet.xml"
49  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
50<programlisting><xi:include href="hello_world_single_code_snippet.xml"
51  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
52</section>
53
54<section><title>Calling Multiple Slots</title>
55<section><title>Connecting Multiple Slots (Beginner)</title>
56<para>Calling a single slot from a signal isn't very interesting, so
57we can make the Hello, World program more interesting by splitting
58the work of printing "Hello, World!" into two completely separate
59slots. The first slot will print "Hello" and may look like
60this:</para>
61<programlisting><xi:include href="hello_def_code_snippet.xml"
62  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
63<para>The second slot will print ", World!" and a newline, to complete
64the program. The second slot may look like this:</para>
65<programlisting><xi:include href="world_def_code_snippet.xml"
66  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
67<para>Like in our previous example, we can create a signal
68<code>sig</code> that takes no arguments and has a
69<code>void</code> return value. This time, we connect both a
70<code>hello</code> and a <code>world</code> slot to the same
71signal, and when we call the signal both slots will be called.</para>
72<programlisting><xi:include href="hello_world_multi_code_snippet.xml"
73  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
74<para>By default, slots are pushed onto the back of the slot list,
75so the output of this program will be as expected:</para>
76<programlisting>
77Hello, World!
78</programlisting>
79</section>
80
81<section><title>Ordering Slot Call Groups (Intermediate)</title>
82<para>Slots are free to have side effects, and that can mean that some
83slots will have to be called before others even if they are not connected in that order. The Boost.Signals2
84library allows slots to be placed into groups that are ordered in
85some way. For our Hello, World program, we want "Hello" to be
86printed before ", World!", so we put "Hello" into a group that must
87be executed before the group that ", World!" is in. To do this, we
88can supply an extra parameter at the beginning of the
89<code>connect</code> call that specifies the group. Group values
90are, by default, <code>int</code>s, and are ordered by the integer
91&lt; relation. Here's how we construct Hello, World:</para>
92<programlisting><xi:include href="hello_world_ordered_code_snippet.xml"
93  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
94<para>Invoking the signal will correctly print "Hello, World!", because the
95<code>Hello</code> object is in group 0, which precedes group 1 where
96the <code>World</code> object resides. The group
97parameter is, in fact, optional. We omitted it in the first Hello,
98World example because it was unnecessary when all of the slots are
99independent. So what happens if we mix calls to connect that use the
100group parameter and those that don't? The "unnamed" slots (i.e., those
101that have been connected without specifying a group name) can be
102placed at the front or back of the slot list (by passing
103<code>boost::signals2::at_front</code> or <code>boost::signals2::at_back</code>
104as the last parameter to <code><methodname
105alt="boost::signals2::signal::connect">connect</methodname></code>, respectively),
106and default to the end of the list. When
107a group is specified, the final <code>at_front</code> or <code>at_back</code>
108parameter describes where the slot
109will be placed within the group ordering.  Ungrouped slots connected with
110<code>at_front</code> will always precede all grouped slots.  Ungrouped
111slots connected with <code>at_back</code> will always succeed all
112grouped slots.
113</para>
114<para>
115  If we add a new slot to our example like this:
116</para>
117<programlisting><xi:include href="good_morning_def_code_snippet.xml"
118  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
119<programlisting><xi:include href="hello_world_ordered_invoke_code_snippet.xml"
120  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
121<para>... we will get the result we wanted:</para>
122<programlisting>
123Hello, World!
124... and good morning!
125</programlisting>
126</section>
127</section>
128
129<section><title>Passing Values to and from Slots</title>
130<section><title>Slot Arguments (Beginner)</title>
131<para>Signals can propagate arguments to each of the slots they call.
132For instance, a signal that propagates mouse motion events might
133want to pass along the new mouse coordinates and whether the mouse
134buttons are pressed.</para>
135<para>As an example, we'll create a signal that passes two
136<code>float</code> arguments to its slots. Then we'll create a few
137slots that print the results of various arithmetic operations on
138these values.</para>
139<programlisting><xi:include href="slot_arguments_slot_defs_code_snippet.xml"
140  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
141<programlisting><xi:include href="slot_arguments_main_code_snippet.xml"
142  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
143<para>This program will print out the following:</para>
144<programlisting>The arguments are 5 and 3
145The sum is 8
146The product is 15
147The difference is 2
148The quotient is 1.66667</programlisting>
149<para>So any values that are given to <code>sig</code> when it is
150called like a function are passed to each of the slots. We have to
151declare the types of these values up front when we create the
152signal. The type <code><classname>boost::signals2::signal</classname>&lt;void (float,
153float)&gt;</code> means that the signal has a <code>void</code>
154return value and takes two <code>float</code> values. Any slot
155connected to <code>sig</code> must therefore be able to take two
156<code>float</code> values.</para>
157</section>
158
159<section><title>Signal Return Values (Advanced)</title>
160<para>Just as slots can receive arguments, they can also return
161values. These values can then be returned back to the caller of the
162signal through a <firstterm>combiner</firstterm>. The combiner is a mechanism
163that can take the results of calling slots (there may be no
164results or a hundred; we don't know until the program runs) and
165coalesces them into a single result to be returned to the caller.
166The single result is often a simple function of the results of the
167slot calls: the result of the last slot call, the maximum value
168returned by any slot, or a container of all of the results are some
169possibilities.</para>
170<para>We can modify our previous arithmetic operations example
171slightly so that the slots all return the results of computing the
172product, quotient, sum, or difference. Then the signal itself can
173return a value based on these results to be printed:</para>
174<programlisting><xi:include href="signal_return_value_slot_defs_code_snippet.xml"
175  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
176<programlisting>boost::signals2::signal&lt;float (float, float)&gt; sig;</programlisting>
177<programlisting><xi:include href="signal_return_value_main_code_snippet.xml"
178  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
179
180<para>This example program will output <code>2</code>. This is because the
181default behavior of a signal that has a return type
182(<code>float</code>, the first template argument given to the
183<code><classname>boost::signals2::signal</classname></code> class template) is to call all slots and
184then return a <classname>boost::optional</classname> containing
185the result returned by the last slot called. This
186behavior is admittedly silly for this example, because slots have
187no side effects and the result is the last slot connected.</para>
188<para>A more interesting signal result would be the maximum of the
189values returned by any slot. To do this, we create a custom
190combiner that looks like this:</para>
191<programlisting><xi:include href="custom_combiners_maximum_def_code_snippet.xml"
192  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
193<para>The <code>maximum</code> class template acts as a function
194object. Its result type is given by its template parameter, and
195this is the type it expects to be computing the maximum based on
196(e.g., <code>maximum&lt;float&gt;</code> would find the maximum
197<code>float</code> in a sequence of <code>float</code>s). When a
198<code>maximum</code> object is invoked, it is given an input
199iterator sequence <code>[first, last)</code> that includes the
200results of calling all of the slots. <code>maximum</code> uses this
201input iterator sequence to calculate the maximum element, and
202returns that maximum value.</para>
203<para>We actually use this new function object type by installing it
204as a combiner for our signal. The combiner template argument
205follows the signal's calling signature:</para>
206<programlisting>
207<classname>boost::signals2::signal</classname>&lt;float (float x, float y),
208              maximum&lt;float&gt; &gt; sig;
209</programlisting>
210<para>Now we can connect slots that perform arithmetic functions and
211use the signal:</para>
212<programlisting><xi:include href="custom_combiners_maximum_usage_code_snippet.xml"
213  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
214<para>The output of this program will be <code>15</code>, because
215regardless of the order in which the slots are connected, the product
216of 5 and 3 will be larger than the quotient, sum, or
217difference.</para>
218<para>In other cases we might want to return all of the values
219computed by the slots together, in one large data structure. This
220is easily done with a different combiner:</para>
221<programlisting><xi:include href="custom_combiners_aggregate_values_def_code_snippet.xml"
222  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
223<para>
224Again, we can create a signal with this new combiner:
225</para>
226<programlisting>
227<classname>boost::signals2::signal</classname>&lt;float (float, float),
228    aggregate_values&lt;std::vector&lt;float&gt; &gt; &gt; sig;</programlisting>
229<programlisting><xi:include href="custom_combiners_aggregate_values_usage_code_snippet.xml"
230  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
231<para>The output of this program will contain 15, 8, 1.6667, and 2. It
232is interesting here that
233the first template argument for the <code>signal</code> class,
234<code>float</code>, is not actually the return type of the signal.
235Instead, it is the return type used by the connected slots and will
236also be the <code>value_type</code> of the input iterators passed
237to the combiner. The combiner itself is a function object and its
238<code>result_type</code> member type becomes the return type of the
239signal.</para>
240<para>The input iterators passed to the combiner transform dereference
241operations into slot calls. Combiners therefore have the option to
242invoke only some slots until some particular criterion is met. For
243instance, in a distributed computing system, the combiner may ask
244each remote system whether it will handle the request. Only one
245remote system needs to handle a particular request, so after a
246remote system accepts the work we do not want to ask any other
247remote systems to perform the same task. Such a combiner need only
248check the value returned when dereferencing the iterator, and
249return when the value is acceptable. The following combiner returns
250the first non-NULL pointer to a <code>FulfilledRequest</code> data
251structure, without asking any later slots to fulfill the
252request:</para>
253<programlisting>
254struct DistributeRequest {
255  typedef FulfilledRequest* result_type;
256
257  template&lt;typename InputIterator&gt;
258  result_type operator()(InputIterator first, InputIterator last) const
259  {
260    while (first != last) {
261      if (result_type fulfilled = *first)
262        return fulfilled;
263      ++first;
264    }
265    return 0;
266  }
267};
268</programlisting>
269</section>
270</section>
271
272<section><title>Connection Management</title>
273<section><title>Disconnecting Slots (Beginner)</title>
274<para>Slots aren't expected to exist indefinitely after they are
275connected. Often slots are only used to receive a few events and
276are then disconnected, and the programmer needs control to decide
277when a slot should no longer be connected.</para>
278<para>The entry point for managing connections explicitly is the
279<code><classname>boost::signals2::connection</classname></code> class. The
280<code>connection</code> class uniquely represents the connection
281between a particular signal and a particular slot. The
282<code><methodname alt="connection::connected">connected</methodname>()</code> method checks if the signal and slot are
283still connected, and the <code><methodname alt="connection::disconnect">disconnect()</methodname></code> method
284disconnects the signal and slot if they are connected before it is
285called. Each call to the signal's <code>connect()</code> method
286returns a connection object, which can be used to determine if the
287connection still exists or to disconnect the signal and slot.</para>
288<programlisting><xi:include href="disconnect_code_snippet.xml"
289  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
290</section>
291
292<section><title>Blocking Slots (Beginner)</title>
293
294<para>Slots can be temporarily "blocked", meaning that they will be
295ignored when the signal is invoked but have not been permanently disconnected.
296This is typically used to prevent infinite recursion in cases where
297otherwise running a slot would cause the signal it is connected to to be
298invoked again.  A
299<classname>boost::signals2::shared_connection_block</classname> object will
300temporarily block a slot.  The connection is unblocked by either
301destroying or calling
302<methodname alt="shared_connection_block::unblock">unblock</methodname>
303on all the
304<code>shared_connection_block</code> objects that reference the connection.
305Here is an example of
306blocking/unblocking slots:</para>
307
308<programlisting><xi:include href="block_code_snippet.xml"
309  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
310
311</section>
312
313<section><title>Scoped Connections (Intermediate)</title>
314<para>The <classname>boost::signals2::scoped_connection</classname> class
315references a signal/slot connection that will be disconnected when
316the <code>scoped_connection</code> class goes out of scope. This
317ability is useful when a connection need only be temporary,
318e.g.,</para>
319<programlisting><xi:include href="scoped_connection_code_snippet.xml"
320  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
321
322<para>
323  Note, attempts to initialize a scoped_connection with the assignment syntax
324  will fail due to it being noncopyable.  Either the explicit initialization syntax
325  or default construction followed by assignment from a <classname>signals2::connection</classname>
326  will work:
327</para>
328<programlisting>
329// doesn't compile due to compiler attempting to copy a temporary scoped_connection object
330// boost::signals2::scoped_connection c0 = sig.<methodname>connect</methodname>(ShortLived());
331
332// okay
333boost::signals2::scoped_connection c1(sig.<methodname>connect</methodname>(ShortLived()));
334
335// also okay
336boost::signals2::scoped_connection c2;
337c2 = sig.<methodname>connect</methodname>(ShortLived());
338</programlisting>
339</section>
340
341<section><title>Disconnecting Equivalent Slots (Intermediate)</title>
342<para>One can disconnect slots that are equivalent to a given function
343object using a form of the
344<code><methodname>signal::disconnect</methodname></code> method, so long as
345the type of the function object has an accessible <code>==</code>
346operator. For instance:
347
348</para>
349<programlisting><xi:include href="disconnect_by_slot_def_code_snippet.xml"
350  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
351<programlisting><classname>boost::signals2::signal</classname>&lt;void ()&gt; sig;</programlisting>
352</section>
353<programlisting><xi:include href="disconnect_by_slot_usage_code_snippet.xml"
354  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
355
356<section id="signals2.tutorial.connection-management"><title>Automatic Connection Management (Intermediate)</title>
357<para>Boost.Signals2 can automatically track the lifetime of objects
358involved in signal/slot connections, including automatic
359disconnection of slots when objects involved in the slot call are
360destroyed. For instance, consider a simple news delivery service,
361where clients connect to a news provider that then sends news to
362all connected clients as information arrives. The news delivery
363service may be constructed like this: </para>
364<programlisting>
365class NewsItem { /* ... */ };
366
367typedef boost::signals2::signal&lt;void (const NewsItem&amp;)&gt; signal_type;
368signal_type deliverNews;
369</programlisting>
370
371<para>Clients that wish to receive news updates need only connect a
372function object that can receive news items to the
373<code>deliverNews</code> signal. For instance, we may have a
374special message area in our application specifically for news,
375e.g.,:</para>
376<programlisting>
377struct NewsMessageArea : public MessageArea
378{
379public:
380  // ...
381
382  void displayNews(const NewsItem&amp; news) const
383  {
384    messageText = news.text();
385    update();
386  }
387};
388
389// ...
390NewsMessageArea *newsMessageArea = new NewsMessageArea(/* ... */);
391// ...
392deliverNews.<methodname>connect</methodname>(boost::bind(&amp;NewsMessageArea::displayNews,
393  newsMessageArea, _1));
394</programlisting>
395<para>However, what if the user closes the news message area,
396destroying the <code>newsMessageArea</code> object that
397<code>deliverNews</code> knows about? Most likely, a segmentation
398fault will occur. However, with Boost.Signals2 one may track any object
399which is managed by a shared_ptr, by using
400<methodname alt="boost::signals2::slot::track">slot::track</methodname>.  A slot will automatically
401disconnect when any of its tracked objects expire.  In
402addition, Boost.Signals2 will ensure that no tracked object expires
403while the slot it is associated with is in mid-execution.  It does so by creating
404temporary shared_ptr copies of the slot's tracked objects before executing it.
405To track <code>NewsMessageArea</code>, we use a shared_ptr to manage
406its lifetime, and pass the shared_ptr to the slot via its
407<methodname alt="boost::signals2::slot::track">slot::track</methodname>
408method before connecting it,
409e.g.:</para>
410<programlisting>
411// ...
412boost::shared_ptr&lt;NewsMessageArea&gt; newsMessageArea(new NewsMessageArea(/* ... */));
413// ...
414deliverNews.<methodname>connect</methodname>(signal_type::slot_type(&amp;NewsMessageArea::displayNews,
415  newsMessageArea.get(), _1).track(newsMessageArea));
416</programlisting>
417<para>
418  Note there is no explicit call to bind() needed in the above example.  If the
419  <classname>signals2::slot</classname> constructor is passed more than one
420  argument, it will automatically pass all the arguments to <code>bind</code> and use the
421  returned function object.
422</para>
423<para>Also note, we pass an ordinary pointer as the
424  second argument to the slot constructor, using <code>newsMessageArea.get()</code>
425  instead of passing the <code>shared_ptr</code> itself.  If we had passed the
426  <code>newsMessageArea</code> itself, a copy of the <code>shared_ptr</code> would
427  have been bound into the slot function, preventing the <code>shared_ptr</code>
428  from expiring.  However, the use of
429  <methodname alt="boost::signals2::slot::track">slot::track</methodname>
430  implies we wish to allow the tracked object to expire, and automatically
431  disconnect the connection when this occurs.
432</para>
433<para>
434  <code>shared_ptr</code> classes other than <classname>boost::shared_ptr</classname>
435  (such as <code>std::shared_ptr</code>) may also be tracked for connection management
436  purposes.  They are supported by the <methodname>slot::track_foreign</methodname> method.
437</para>
438</section>
439
440  <section id="signals2.tutorial.deconstruct">
441    <title>Postconstructors and Predestructors (Advanced)</title>
442    <para>One limitation of using <code>shared_ptr</code> for tracking is that
443      an object cannot setup tracking of itself in its constructor.  However, it is
444      possible to set up tracking in a post-constructor which is called after the
445      object has been created and passed to a <classname>shared_ptr</classname>.
446      The Boost.Signals2
447      library provides support for post-constructors and pre-destructors
448      via the <functionname>deconstruct()</functionname> factory function.
449    </para>
450    <para>
451      For most cases, the simplest and most robust way to setup postconstructors
452      for a class is to define an associated <code>adl_postconstruct</code> function
453      which can be found by <functionname>deconstruct()</functionname>,
454      make the class' constructors private, and give <functionname>deconstruct</functionname>
455      access to the private constructors by declaring <classname>deconstruct_access</classname>
456      a friend.  This will ensure that objects of the class may only be created
457      through the <functionname>deconstruct()</functionname> function, and their
458      associated <code>adl_postconstruct()</code> function will always be called.
459    </para>
460    <para>The <link linkend="signals2.examples.deconstruct">examples</link> section
461      contains several examples of defining classes with postconstructors and
462      predestructors, and creating objects of these classes using
463      <functionname>deconstruct()</functionname>
464    </para>
465    <para>
466      Be aware that the postconstructor/predestructor support in Boost.Signals2
467      is in no way essential to the use of the library.  The use of
468      <functionname>deconstruct</functionname>
469      is purely optional.  One alternative is to
470      define static factory functions for your classes.  The
471      factory function can create an object, pass ownership of the object to
472      a <classname>shared_ptr</classname>, setup tracking for the object,
473      then return the <classname>shared_ptr</classname>.
474    </para>
475  </section>
476
477<section><title>When Can Disconnections Occur? (Intermediate)</title>
478<para>Signal/slot disconnections occur when any of these conditions
479occur:</para>
480<itemizedlist>
481<listitem><para>The connection is explicitly disconnected via the connection's
482<code>disconnect</code> method directly, or indirectly via the
483signal's <code>disconnect</code> method, or
484<code>scoped_connection</code>'s destructor.</para></listitem>
485<listitem><para>An object tracked by the slot is
486destroyed.</para></listitem>
487<listitem><para>The signal is destroyed.</para></listitem></itemizedlist>
488<para>These events can occur at any time without disrupting a signal's
489calling sequence. If a signal/slot connection is disconnected at
490any time during a signal's calling sequence, the calling sequence
491will still continue but will not invoke the disconnected slot.
492Additionally, a signal may be destroyed while it is in a calling
493sequence, in which case it will complete its slot call sequence
494but may not be accessed directly.</para>
495<para>Signals may be invoked recursively (e.g., a signal A calls a
496slot B that invokes signal A...). The disconnection behavior does
497not change in the recursive case, except that the slot calling
498sequence includes slot calls for all nested invocations of the
499signal.</para>
500<para>
501  Note, even after a connection is disconnected, its's associated slot
502  may still be in the process of executing.  In other words, disconnection
503  does not block waiting for the connection's associated slot to complete execution.
504  This situation may occur in a multi-threaded environment if the
505  disconnection occurs concurrently with signal invocation,
506  or in a single-threaded environment if a slot disconnects itself.
507</para>
508</section>
509
510<section><title>Passing Slots (Intermediate)</title>
511<para>Slots in the Boost.Signals2 library are created from arbitrary
512function objects, and therefore have no fixed type. However, it is
513commonplace to require that slots be passed through interfaces that
514cannot be templates. Slots can be passed via the
515<code>slot_type</code> for each particular signal type and any
516function object compatible with the signature of the signal can be
517passed to a <code>slot_type</code> parameter. For instance:</para>
518<programlisting><xi:include href="passing_slots_defs_code_snippet.xml"
519  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
520<programlisting>
521<xi:include href="passing_slots_usage_code_snippet.xml"
522  xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
523
524<para>The <code>doOnClick</code> method is now functionally equivalent
525to the <code>connect</code> method of the <code>onClick</code>
526signal, but the details of the <code>doOnClick</code> method can be
527hidden in an implementation detail file.</para>
528</section>
529</section>
530
531<section id="signals2.tutorial.document-view">
532  <title>Example: Document-View</title>
533
534  <para>Signals can be used to implement flexible Document-View
535  architectures. The document will contain a signal to which each of
536  the views can connect. The following <code>Document</code> class
537  defines a simple text document that supports mulitple views. Note
538  that it stores a single signal to which all of the views will be
539  connected.</para>
540
541  <programlisting><xi:include href="document_def_code_snippet.xml"
542    xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
543
544  <para>
545    Next, we can begin to define views. The
546    following <code>TextView</code> class provides a simple view of the
547    document text.
548  </para>
549
550  <programlisting><xi:include href="text_view_def_code_snippet.xml"
551    xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
552
553  <para>Alternatively, we can provide a view of the document
554    translated into hex values using the <code>HexView</code>
555    view:</para>
556
557  <programlisting><xi:include href="hex_view_def_code_snippet.xml"
558    xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
559
560  <para>
561    To tie the example together, here is a
562    simple <code>main</code> function that sets up two views and then
563    modifies the document:
564  </para>
565
566  <programlisting><xi:include href="document_view_main_code_snippet.xml"
567    xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml"/></programlisting>
568
569  <para>The complete example source, contributed by Keith MacDonald,
570    is available in the <link linkend="signals2.examples.document-view">examples</link> section.
571    We also provide variations on the program which employ automatic connection management
572    to disconnect views on their destruction.
573  </para>
574</section>
575
576  <section id="signals2.tutorial.extended-slot-type">
577    <title>Giving a Slot Access to its Connection (Advanced)</title>
578    <para>
579      You may encounter situations where you wish to disconnect or block a slot's
580      connection from within the slot itself.  For example, suppose you have a group
581      of asynchronous tasks, each of which emits a signal when it completes.
582      You wish to connect a slot to all the tasks to retrieve their results as
583      each completes.  Once a
584      given task completes and the slot is run, the slot no longer needs to be
585      connected to the completed task.
586      Therefore, you may wish to clean up old connections by having the slot
587      disconnect its invoking connection when it runs.
588    </para>
589    <para>
590      For a slot to disconnect (or block) its invoking connection, it must have
591      access to a <classname>signals2::connection</classname> object which references
592      the invoking signal-slot connection.  The difficulty is,
593      the <code>connection</code> object is returned by the
594      <methodname>signal::connect</methodname>
595      method, and therefore is not available until after the slot is
596      already connected to the signal.  This can be particularly troublesome
597      in a multi-threaded environment where the signal may be invoked
598      concurrently by a different thread while the slot is being connected.
599    </para>
600    <para>
601      Therefore, the signal classes provide
602      <methodname>signal::connect_extended</methodname>
603      methods, which allow slots which take an extra argument to be connected to a signal.
604      The extra argument is a <classname>signals2::connection</classname> object which refers
605      to the signal-slot connection currently invoking the slot.
606      <methodname>signal::connect_extended</methodname>
607      uses slots of the type given by the
608      <classname>signal::extended_slot_type</classname>
609      typedef.
610    </para>
611    <para>
612      The examples section includes an
613      <link linkend="signals2.examples.tutorial.extended_slot">extended_slot</link>
614      program which demonstrates the syntax for using
615      <methodname>signal::connect_extended</methodname>.
616    </para>
617  </section>
618
619  <section id="signals2.tutorial.signal-mutex-template-parameter">
620    <title>Changing the <code>Mutex</code> Type of a Signal (Advanced).</title>
621    <para>
622      For most cases the default type of <classname>boost::signals2::mutex</classname> for
623      a <classname>signals2::signal</classname>'s <code>Mutex</code> template type parameter should
624      be fine.  If you wish to use an alternate mutex type, it must be default-constructible
625      and fulfill the <code>Lockable</code> concept defined by the Boost.Thread library.
626      That is, it must have <code>lock()</code> and <code>unlock()</code> methods
627      (the <code>Lockable</code> concept also includes a <code>try_lock()</code> method
628      but this library does not require try locking).
629    </para>
630    <para>
631      The Boost.Signals2 library provides one alternate mutex class for use with <code>signal</code>:
632      <classname>boost::signals2::dummy_mutex</classname>.  This is a fake mutex for
633      use in single-threaded programs, where locking a real mutex would be useless
634      overhead.  Other mutex types you could use with <code>signal</code> include
635      <classname>boost::mutex</classname>, or the <code>std::mutex</code> from
636      C++11.
637    </para>
638    <para>
639      Changing a signal's <code>Mutex</code> template type parameter can be tedious, due to
640      the large number of template parameters which precede it.  The
641      <classname>signal_type</classname> metafunction is particularly useful in this case,
642      since it enables named template type parameters for the <classname>signals2::signal</classname>
643      class.  For example, to declare a signal which takes an <code>int</code> as
644      an argument and uses a <classname>boost::signals2::dummy_mutex</classname>
645      for its <code>Mutex</code> types, you could write:
646    </para>
647<programlisting>namespace bs2 = boost::signals2;
648using namespace bs2::keywords;
649bs2::signal_type&lt;void (int), mutex_type&lt;bs2::dummy_mutex&gt; &gt;::type sig;
650</programlisting>
651
652  </section>
653
654  <section>
655    <title>Linking against the Signals2 library</title>
656    <para>Unlike the original Boost.Signals library, Boost.Signals2 is currently header-only.
657    </para>
658  </section>
659
660</section>
661