Imported Upstream version 1.57.0
[platform/upstream/boost.git] / libs / signals / doc / tutorial.xml
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 <section last-revision="$Date$" id="signals.tutorial">
5   <title>Tutorial</title>
6
7   <using-namespace name="boost"/>
8   <using-namespace name="boost::signals"/>
9   <using-class name="boost::signalN"/>
10
11   <section>
12     <title>How to Read this Tutorial</title>
13 <para>This tutorial is not meant to be read linearly. Its top-level
14 structure roughly separates different concepts in the library
15 (e.g., handling calling multiple slots, passing values to and from
16 slots) and in each of these concepts the basic ideas are presented
17 first and then more complex uses of the library are described
18 later. Each of the sections is marked <emphasis>Beginner</emphasis>,
19 <emphasis>Intermediate</emphasis>, or <emphasis>Advanced</emphasis> to help guide the
20 reader. The <emphasis>Beginner</emphasis> sections include information that all
21 library users should know; one can make good use of the Signals
22 library after having read only the <emphasis>Beginner</emphasis> sections. The
23 <emphasis>Intermediate</emphasis> sections build on the <emphasis>Beginner</emphasis>
24 sections with slightly more complex uses of the library. Finally,
25 the <emphasis>Advanced</emphasis> sections detail very advanced uses of the
26 Signals library, that often require a solid working knowledge of
27 the <emphasis>Beginner</emphasis> and <emphasis>Intermediate</emphasis> topics; most users
28 will not need to read the <emphasis>Advanced</emphasis> sections.</para>
29 </section>
30
31 <section><title>Compatibility Note</title> 
32
33 <para>Boost.Signals has two syntactical forms: the preferred form and
34 the compatibility form. The preferred form fits more closely with the
35 C++ language and reduces the number of separate template parameters
36 that need to be considered, often improving readability; however, the
37 preferred form is not supported on all platforms due to compiler
38 bugs. The compatible form will work on all compilers supported by
39 Boost.Signals. Consult the table below to determine which syntactic
40 form to use for your compiler. Users of Boost.Function, please note
41 that the preferred syntactic form in Signals is equivalent to that of
42 Function's preferred syntactic form.</para>
43
44 <para>If your compiler does not appear in this list, please try the
45 preferred syntax and report your results to the Boost list so that
46 we can keep this table up-to-date.</para>
47
48   <informaltable>
49     <tgroup cols="2" align="left">
50       <thead>
51         <row>
52           <entry>Preferred syntax</entry>
53           <entry>Portable syntax</entry>
54         </row>
55       </thead>
56       <tbody>
57         <row>
58           <entry>
59             <itemizedlist>
60               <listitem><para>GNU C++ 2.95.x, 3.0.x, 3.1.x</para></listitem>
61               <listitem><para>Comeau C++ 4.2.45.2</para></listitem>
62               <listitem><para>SGI MIPSpro 7.3.0</para></listitem>
63               <listitem><para>Intel C++ 5.0, 6.0</para></listitem>
64               <listitem><para>Compaq's cxx 6.2</para></listitem>
65               <listitem><para>Microsoft Visual C++ 7.1</para></listitem>
66             </itemizedlist>
67           </entry>
68           <entry>
69             <itemizedlist>
70               <listitem><para><emphasis>Any compiler supporting the preferred syntax</emphasis></para></listitem>
71               <listitem><para>Microsoft Visual C++ 6.0, 7.0</para></listitem>
72               <listitem><para>Borland C++ 5.5.1</para></listitem>
73               <listitem><para>Sun WorkShop 6 update 2 C++ 5.3</para></listitem>
74               <listitem><para>Metrowerks CodeWarrior 8.1</para></listitem>
75             </itemizedlist>
76           </entry>
77         </row>
78       </tbody>
79     </tgroup>
80   </informaltable>
81 </section>
82
83 <section><title>Hello, World! (Beginner)</title>
84 <para>The following example writes "Hello, World!" using signals and
85 slots. First, we create a signal <code>sig</code>, a signal that
86 takes no arguments and has a void return value. Next, we connect
87 the <code>hello</code> function object to the signal using the
88 <code>connect</code> method. Finally, use the signal
89 <code>sig</code> like a function to call the slots, which in turns
90 invokes <code>HelloWorld::operator()</code> to print "Hello,
91 World!".</para>
92   <informaltable>
93     <tgroup cols="2" align="left">
94       <thead>
95         <row>
96           <entry>Preferred syntax</entry>
97           <entry>Portable syntax</entry>
98         </row>
99       </thead>
100       <tbody>
101         <row>
102           <entry>
103 <programlisting>
104 struct HelloWorld 
105 {
106   void operator()() const 
107   { 
108     std::cout &lt;&lt; "Hello, World!" &lt;&lt; std::endl;
109   } 
110 };
111
112 // ...
113
114 // Signal with no arguments and a void return value
115 <classname>boost::signal</classname>&lt;void ()&gt; sig;
116
117 // Connect a HelloWorld slot
118 HelloWorld hello;
119 sig.<methodname>connect</methodname>(hello);
120
121 // Call all of the slots
122 sig();
123 </programlisting>
124 </entry>
125 <entry>
126 <programlisting>
127 struct HelloWorld 
128 {
129   void operator()() const 
130   { 
131     std::cout &lt;&lt; "Hello, World!" &lt;&lt; std::endl;
132   } 
133 };
134
135 // ...
136
137 // Signal with no arguments and a void return value
138 <classname alt="boost::signalN">boost::signal0</classname>&lt;void&gt; sig;
139
140 // Connect a HelloWorld slot
141 HelloWorld hello;
142 sig.<methodname>connect</methodname>(hello);
143
144 // Call all of the slots
145 sig();
146 </programlisting>
147 </entry>
148           </row>
149         </tbody>
150       </tgroup>
151     </informaltable>
152 </section>
153
154 <section><title>Calling multiple slots</title>
155 <section><title>Connecting multiple slots (Beginner)</title>
156 <para>Calling a single slot from a signal isn't very interesting, so
157 we can make the Hello, World program more interesting by splitting
158 the work of printing "Hello, World!" into two completely separate
159 slots. The first slot will print "Hello" and may look like
160 this:</para>
161 <programlisting>
162 struct Hello 
163 {
164   void operator()() const
165   {
166     std::cout &lt;&lt; "Hello";
167   }
168 };
169 </programlisting>
170 <para>The second slot will print ", World!" and a newline, to complete
171 the program. The second slot may look like this:</para>
172 <programlisting>
173 struct World
174 {
175   void operator()() const
176   {
177     std::cout &lt;&lt; ", World!" &lt;&lt; std::endl;
178   }
179 };
180 </programlisting>
181 <para>Like in our previous example, we can create a signal
182 <code>sig</code> that takes no arguments and has a
183 <code>void</code> return value. This time, we connect both a
184 <code>hello</code> and a <code>world</code> slot to the same
185 signal, and when we call the signal both slots will be called.</para>
186   <informaltable>
187     <tgroup cols="2" align="left">
188       <thead>
189         <row>
190           <entry>Preferred syntax</entry>
191           <entry>Portable syntax</entry>
192         </row>
193       </thead>
194       <tbody>
195         <row>
196           <entry>
197 <programlisting>
198 <classname>boost::signal</classname>&lt;void ()&gt; sig;
199
200 sig.<methodname>connect</methodname>(Hello());
201 sig.<methodname>connect</methodname>(World());
202
203 sig();
204 </programlisting>
205 </entry>
206 <entry>
207 <programlisting>
208 <classname alt="boost::signalN">boost::signal0</classname>&lt;void&gt; sig;
209
210 sig.<methodname>connect</methodname>(Hello());
211 sig.<methodname>connect</methodname>(World());
212
213 sig();
214 </programlisting>
215 </entry>
216             </row>
217           </tbody>
218         </tgroup>
219       </informaltable>
220 <para>By default, slots are called in first-in first-out (FIFO) order,
221 so the output of this program will be as expected:</para>
222 <programlisting>
223 Hello, World!
224 </programlisting>
225 </section>
226
227 <section><title>Ordering slot call groups (Intermediate)</title>
228 <para>Slots are free to have side effects, and that can mean that some
229 slots will have to be called before others even if they are not connected in that order. The Boost.Signals
230 library allows slots to be placed into groups that are ordered in
231 some way. For our Hello, World program, we want "Hello" to be
232 printed before ", World!", so we put "Hello" into a group that must
233 be executed before the group that ", World!" is in. To do this, we
234 can supply an extra parameter at the beginning of the
235 <code>connect</code> call that specifies the group. Group values
236 are, by default, <code>int</code>s, and are ordered by the integer
237 &lt; relation. Here's how we construct Hello, World:</para>
238   <informaltable>
239     <tgroup cols="2" align="left">
240       <thead>
241         <row>
242           <entry>Preferred syntax</entry>
243           <entry>Portable syntax</entry>
244         </row>
245       </thead>
246       <tbody>
247         <row>
248           <entry>
249 <programlisting>
250 <classname>boost::signal</classname>&lt;void ()&gt; sig;
251 sig.<methodname>connect</methodname>(1, World());
252 sig.<methodname>connect</methodname>(0, Hello());
253 sig();
254 </programlisting>
255 </entry>
256             <entry>
257 <programlisting>
258 <classname alt="boost::signalN">boost::signal0</classname>&lt;void&gt; sig;
259 sig.<methodname>connect</methodname>(1, World());
260 sig.<methodname>connect</methodname>(0, Hello());
261 sig();
262 </programlisting>
263 </entry>
264             </row>
265           </tbody>
266         </tgroup>
267       </informaltable>
268
269 <para>This program will correctly print "Hello, World!", because the
270 <code>Hello</code> object is in group 0, which precedes group 1 where
271 the <code>World</code> object resides. The group
272 parameter is, in fact, optional. We omitted it in the first Hello,
273 World example because it was unnecessary when all of the slots are
274 independent. So what happens if we mix calls to connect that use the
275 group parameter and those that don't? The "unnamed" slots (i.e., those
276 that have been connected without specifying a group name) can be
277 placed at the front or back of the slot list (by passing
278 <code>boost::signals::at_front</code> or <code>boost::signals::at_back</code>
279 as the last parameter to <code><methodname
280 alt="boost::signalN::connect">connect</methodname></code>, respectively), and defaults to the end of the list. When
281 a group is specified, the final parameter describes where the slot
282 will be placed within the group ordering. If we add a new slot
283 to our example like this:</para>
284 <programlisting>
285 struct GoodMorning
286 {
287   void operator()() const
288   {
289     std::cout &lt;&lt; "... and good morning!" &lt;&lt; std::endl;
290   }
291 };
292
293 sig.<methodname>connect</methodname>(GoodMorning());
294 </programlisting>
295 <para>... we will get the result we wanted:</para>
296 <programlisting>
297 Hello, World!
298 ... and good morning!
299 </programlisting>
300 </section>
301 </section>
302
303 <section><title>Passing values to and from slots</title>
304 <section><title>Slot Arguments (Beginner)</title>
305 <para>Signals can propagate arguments to each of the slots they call.
306 For instance, a signal that propagates mouse motion events might
307 want to pass along the new mouse coordinates and whether the mouse
308 buttons are pressed.</para>
309 <para>As an example, we'll create a signal that passes two
310 <code>float</code> arguments to its slots. Then we'll create a few
311 slots that print the results of various arithmetic operations on
312 these values.</para>
313 <programlisting>
314 void print_sum(float x, float y)
315 {
316   std::cout &lt;&lt; "The sum is " &lt;&lt; x+y &lt;&lt; std::endl;
317 }
318
319 void print_product(float x, float y)
320 {
321   std::cout &lt;&lt; "The product is " &lt;&lt; x*y &lt;&lt; std::endl;
322 }
323
324 void print_difference(float x, float y)
325 {
326   std::cout &lt;&lt; "The difference is " &lt;&lt; x-y &lt;&lt; std::endl;
327 }
328
329 void print_quotient(float x, float y)
330 {
331   std::cout &lt;&lt; "The quotient is " &lt;&lt; x/y &lt;&lt; std::endl;
332 }
333 </programlisting>
334
335   <informaltable>
336     <tgroup cols="2" align="left">
337       <thead>
338         <row>
339           <entry>Preferred syntax</entry>
340           <entry>Portable syntax</entry>
341         </row>
342       </thead>
343       <tbody>
344         <row>
345           <entry>
346 <programlisting>
347 <classname>boost::signal</classname>&lt;void (float, float)&gt; sig;
348
349 sig.<methodname>connect</methodname>(&amp;print_sum);
350 sig.<methodname>connect</methodname>(&amp;print_product);
351 sig.<methodname>connect</methodname>(&amp;print_difference);
352 sig.<methodname>connect</methodname>(&amp;print_quotient);
353
354 sig(5, 3);
355 </programlisting>
356 </entry>
357 <entry>
358 <programlisting>
359 <classname alt="boost::signalN">boost::signal2</classname>&lt;void, float, float&gt; sig;
360
361 sig.<methodname>connect</methodname>(&amp;print_sum);
362 sig.<methodname>connect</methodname>(&amp;print_product);
363 sig.<methodname>connect</methodname>(&amp;print_difference);
364 sig.<methodname>connect</methodname>(&amp;print_quotient);
365
366 sig(5, 3);
367 </programlisting>
368 </entry>
369               </row>
370             </tbody>
371           </tgroup>
372         </informaltable>
373
374 <para>This program will print out the following:</para>
375 <programlisting>
376 The sum is 8
377 The product is 15
378 The difference is 2
379 The quotient is 1.66667
380 </programlisting>
381 <para>So any values that are given to <code>sig</code> when it is
382 called like a function are passed to each of the slots. We have to
383 declare the types of these values up front when we create the
384 signal. The type <code><classname>boost::signal</classname>&lt;void (float,
385 float)&gt;</code> means that the signal has a <code>void</code>
386 return value and takes two <code>float</code> values. Any slot
387 connected to <code>sig</code> must therefore be able to take two
388 <code>float</code> values.</para>
389 </section>
390
391 <section><title>Signal Return Values (Advanced)</title>
392 <para>Just as slots can receive arguments, they can also return
393 values. These values can then be returned back to the caller of the
394 signal through a <firstterm>combiner</firstterm>. The combiner is a mechanism
395 that can take the results of calling slots (there many be no
396 results or a hundred; we don't know until the program runs) and
397 coalesces them into a single result to be returned to the caller.
398 The single result is often a simple function of the results of the
399 slot calls: the result of the last slot call, the maximum value
400 returned by any slot, or a container of all of the results are some
401 possibilities.</para>
402 <para>We can modify our previous arithmetic operations example
403 slightly so that the slots all return the results of computing the
404 product, quotient, sum, or difference. Then the signal itself can
405 return a value based on these results to be printed:</para>
406   <informaltable>
407     <tgroup cols="2" align="left">
408       <thead>
409         <row>
410           <entry>Preferred syntax</entry>
411           <entry>Portable syntax</entry>
412         </row>
413       </thead>
414       <tbody>
415         <row>
416           <entry>
417 <programlisting>
418 float product(float x, float y) { return x*y; }
419 float quotient(float x, float y) { return x/y; }
420 float sum(float x, float y) { return x+y; }
421 float difference(float x, float y) { return x-y; }
422
423 <classname>boost::signal</classname>&lt;float (float x, float y)&gt; sig;
424
425 sig.<methodname>connect</methodname>(&amp;product);
426 sig.<methodname>connect</methodname>(&amp;quotient);
427 sig.<methodname>connect</methodname>(&amp;sum);
428 sig.<methodname>connect</methodname>(&amp;difference);
429
430 std::cout &lt;&lt; sig(5, 3) &lt;&lt; std::endl;
431 </programlisting>
432 </entry>
433 <entry>
434 <programlisting>
435 float product(float x, float y) { return x*y; }
436 float quotient(float x, float y) { return x/y; }
437 float sum(float x, float y) { return x+y; }
438 float difference(float x, float y) { return x-y; }
439
440 <classname alt="boost::signalN">boost::signal2</classname>&lt;float, float, float&gt; sig;
441
442 sig.<methodname>connect</methodname>(&amp;product);
443 sig.<methodname>connect</methodname>(&amp;quotient);
444 sig.<methodname>connect</methodname>(&amp;sum);
445 sig.<methodname>connect</methodname>(&amp;difference);
446
447 std::cout &lt;&lt; sig(5, 3) &lt;&lt; std::endl;
448 </programlisting>
449 </entry>
450             </row>
451           </tbody>
452         </tgroup>
453       </informaltable>
454
455 <para>This example program will output <code>2</code>. This is because the
456 default behavior of a signal that has a return type
457 (<code>float</code>, the first template argument given to the
458 <code><classname>boost::signal</classname></code> class template) is to call all slots and
459 then return the result returned by the last slot called. This
460 behavior is admittedly silly for this example, because slots have
461 no side effects and the result is the last slot connect.</para>
462 <para>A more interesting signal result would be the maximum of the
463 values returned by any slot. To do this, we create a custom
464 combiner that looks like this:</para>
465 <programlisting>
466 template&lt;typename T&gt;
467 struct maximum
468 {
469   typedef T result_type;
470
471   template&lt;typename InputIterator&gt;
472   T operator()(InputIterator first, InputIterator last) const
473   {
474     // If there are no slots to call, just return the
475     // default-constructed value
476     if (first == last)
477       return T();
478
479     T max_value = *first++;
480     while (first != last) {
481       if (max_value &lt; *first)
482         max_value = *first;
483       ++first;
484     }
485   
486     return max_value;
487   }
488 };
489 </programlisting>
490 <para>The <code>maximum</code> class template acts as a function
491 object. Its result type is given by its template parameter, and
492 this is the type it expects to be computing the maximum based on
493 (e.g., <code>maximum&lt;float&gt;</code> would find the maximum
494 <code>float</code> in a sequence of <code>float</code>s). When a
495 <code>maximum</code> object is invoked, it is given an input
496 iterator sequence <code>[first, last)</code> that includes the
497 results of calling all of the slots. <code>maximum</code> uses this
498 input iterator sequence to calculate the maximum element, and
499 returns that maximum value.</para>
500 <para>We actually use this new function object type by installing it
501 as a combiner for our signal. The combiner template argument
502 follows the signal's calling signature:</para>
503   <informaltable>
504     <tgroup cols="2" align="left">
505       <thead>
506         <row>
507           <entry>Preferred syntax</entry>
508           <entry>Portable syntax</entry>
509         </row>
510       </thead>
511       <tbody>
512         <row>
513           <entry>
514 <programlisting>
515 <classname>boost::signal</classname>&lt;float (float x, float y), 
516               maximum&lt;float&gt; &gt; sig;
517 </programlisting>
518 </entry>
519 <entry>
520 <programlisting>
521 <classname alt="boost::signalN">boost::signal2</classname>&lt;float, float, float, 
522                maximum&lt;float&gt; &gt; sig;
523 </programlisting>
524 </entry>
525             </row>
526           </tbody>
527         </tgroup>
528       </informaltable>
529
530 <para>Now we can connect slots that perform arithmetic functions and
531 use the signal:</para>
532 <programlisting>
533 sig.<methodname>connect</methodname>(&amp;quotient);
534 sig.<methodname>connect</methodname>(&amp;product);
535 sig.<methodname>connect</methodname>(&amp;sum);
536 sig.<methodname>connect</methodname>(&amp;difference);
537
538 std::cout &lt;&lt; sig(5, 3) &lt;&lt; std::endl;
539 </programlisting>
540 <para>The output of this program will be <code>15</code>, because
541 regardless of the order in which the slots are connected, the product
542 of 5 and 3 will be larger than the quotient, sum, or
543 difference.</para>
544 <para>In other cases we might want to return all of the values
545 computed by the slots together, in one large data structure. This
546 is easily done with a different combiner:</para>
547 <programlisting>
548 template&lt;typename Container&gt;
549 struct aggregate_values
550 {
551   typedef Container result_type;
552
553   template&lt;typename InputIterator&gt;
554   Container operator()(InputIterator first, InputIterator last) const
555   {
556     return Container(first, last);
557   }
558 };
559 </programlisting>
560 <para>
561 Again, we can create a signal with this new combiner: 
562 </para>
563   <informaltable>
564     <tgroup cols="2" align="left">
565       <thead>
566         <row>
567           <entry>Preferred syntax</entry>
568           <entry>Portable syntax</entry>
569         </row>
570       </thead>
571       <tbody>
572         <row>
573           <entry>
574 <programlisting>
575 <classname>boost::signal</classname>&lt;float (float, float), 
576     aggregate_values&lt;std::vector&lt;float&gt; &gt; &gt; sig;
577
578 sig.<methodname>connect</methodname>(&amp;quotient);
579 sig.<methodname>connect</methodname>(&amp;product);
580 sig.<methodname>connect</methodname>(&amp;sum);
581 sig.<methodname>connect</methodname>(&amp;difference);
582
583 std::vector&lt;float&gt; results = sig(5, 3);
584 std::copy(results.begin(), results.end(), 
585     std::ostream_iterator&lt;float&gt;(cout, " "));
586 </programlisting>
587 </entry>
588 <entry>
589 <programlisting>
590 <classname alt="boost::signalN">boost::signal2</classname>&lt;float, float, float,
591     aggregate_values&lt;std::vector&lt;float&gt; &gt; &gt; sig;
592
593 sig.<methodname>connect</methodname>(&amp;quotient);
594 sig.<methodname>connect</methodname>(&amp;product);
595 sig.<methodname>connect</methodname>(&amp;sum);
596 sig.<methodname>connect</methodname>(&amp;difference);
597
598 std::vector&lt;float&gt; results = sig(5, 3);
599 std::copy(results.begin(), results.end(), 
600     std::ostream_iterator&lt;float&gt;(cout, " "));
601 </programlisting>
602 </entry>
603             </row>
604           </tbody>
605         </tgroup>
606       </informaltable>
607
608 <para>The output of this program will contain 15, 8, 1.6667, and 2. It
609 is interesting here that
610 the first template argument for the <code>signal</code> class,
611 <code>float</code>, is not actually the return type of the signal.
612 Instead, it is the return type used by the connected slots and will
613 also be the <code>value_type</code> of the input iterators passed
614 to the combiner. The combiner itself is a function object and its
615 <code>result_type</code> member type becomes the return type of the
616 signal.</para>
617 <para>The input iterators passed to the combiner transform dereference
618 operations into slot calls. Combiners therefore have the option to
619 invoke only some slots until some particular criterion is met. For
620 instance, in a distributed computing system, the combiner may ask
621 each remote system whether it will handle the request. Only one
622 remote system needs to handle a particular request, so after a
623 remote system accepts the work we do not want to ask any other
624 remote systems to perform the same task. Such a combiner need only
625 check the value returned when dereferencing the iterator, and
626 return when the value is acceptable. The following combiner returns
627 the first non-NULL pointer to a <code>FulfilledRequest</code> data
628 structure, without asking any later slots to fulfill the
629 request:</para>
630 <programlisting>
631 struct DistributeRequest {
632   typedef FulfilledRequest* result_type;
633
634   template&lt;typename InputIterator&gt;
635   result_type operator()(InputIterator first, InputIterator last) const
636   {
637     while (first != last) {
638       if (result_type fulfilled = *first)
639         return fulfilled;
640       ++first;
641     }
642     return 0;
643   }
644 };
645 </programlisting>
646 </section>
647 </section>
648
649 <section><title>Connection Management</title>
650 <section><title>Disconnecting Slots (Beginner)</title>
651 <para>Slots aren't expected to exist indefinately after they are
652 connected. Often slots are only used to receive a few events and
653 are then disconnected, and the programmer needs control to decide
654 when a slot should no longer be connected.</para>
655 <para>The entry point for managing connections explicitly is the
656 <code><classname>boost::signals::connection</classname></code> class. The
657 <code><classname>connection</classname></code> class uniquely represents the connection
658 between a particular signal and a particular slot. The
659 <code><methodname alt="connection::connected">connected</methodname>()</code> method checks if the signal and slot are
660 still connected, and the <code><methodname alt="connection::disconnect">disconnect()</methodname></code> method
661 disconnects the signal and slot if they are connected before it is
662 called. Each call to the signal's <code>connect()</code> method
663 returns a connection object, which can be used to determine if the
664 connection still exists or to disconnect the signal and slot.</para>
665 <programlisting>
666 boost::signals::connection c = sig.<methodname>connect</methodname>(HelloWorld());
667 if (c.<methodname>connected</methodname>()) {
668 <emphasis>// c is still connected to the signal</emphasis>
669   sig(); <emphasis>// Prints "Hello, World!"</emphasis>
670 }
671
672 c.disconnect(); <emphasis>// Disconnect the HelloWorld object</emphasis>
673 assert(!c.<methodname>connected</methodname>()); <emphasis>c isn't connected any more</emphasis>
674
675 sig(); <emphasis>// Does nothing: there are no connected slots</emphasis>
676 </programlisting>
677 </section>
678
679 <section><title>Blocking Slots (Beginner)</title> 
680
681 <para>Slots can be temporarily "blocked", meaning that they will be
682 ignored when the signal is invoked but have not been disconnected. The
683 <code><methodname>block</methodname></code> member function
684 temporarily blocks a slot, which can be unblocked via
685 <code><methodname>unblock</methodname></code>. Here is an example of
686 blocking/unblocking slots:</para>
687
688 <programlisting>
689 boost::signals::connection c = sig.<methodname>connect</methodname>(HelloWorld());
690 sig(); <emphasis>// Prints "Hello, World!"</emphasis>
691
692 c.<methodname>block</methodname>(); <emphasis>// block the slot</emphasis>
693 assert(c.<methodname>blocked</methodname>());
694 sig(); <emphasis>// No output: the slot is blocked</emphasis>
695
696 c.<methodname>unblock</methodname>(); <emphasis>// unblock the slot</emphasis>
697 sig(); <emphasis>// Prints "Hello, World!"</emphasis>
698 </programlisting>
699
700 </section>
701
702 <section><title>Scoped connections (Intermediate)</title>
703 <para>The <code>boost::signals::scoped_connection</code> class
704 references a signal/slot connection that will be disconnected when
705 the <code>scoped_connection</code> class goes out of scope. This
706 ability is useful when a connection need only be temporary,
707 e.g.,</para>
708 <programlisting>
709 {
710   boost::signals::scoped_connection c = sig.<methodname>connect</methodname>(ShortLived());
711   sig(); <emphasis>// will call ShortLived function object</emphasis>
712 }
713 sig(); <emphasis>// ShortLived function object no longer connected to sig</emphasis>
714 </programlisting>
715 </section>
716
717 <section><title>Disconnecting equivalent slots (Intermediate)</title>
718 <para>One can disconnect slots that are equivalent to a given function
719 object using a form of the
720 <code><methodname>disconnect</methodname></code> method, so long as
721 the type of the function object has an accessible <code>==</code>
722 operator. For instance:
723
724 </para>
725   <informaltable>
726     <tgroup cols="2" align="left">
727       <thead>
728         <row>
729           <entry>Preferred syntax</entry>
730           <entry>Portable syntax</entry>
731         </row>
732       </thead>
733       <tbody>
734         <row>
735           <entry>
736 <programlisting>
737 void foo();
738 void bar();
739
740 signal&lt;void()&gt; sig;
741
742 sig.connect(&amp;foo);
743 sig.connect(&amp;bar);
744
745 // disconnects foo, but not bar
746 sig.disconnect(&amp;foo);
747 </programlisting>
748 </entry>
749 <entry>
750 <programlisting>
751 void foo();
752 void bar();
753
754 signal0&lt;void&gt; sig;
755
756 sig.connect(&amp;foo);
757 sig.connect(&amp;bar);
758
759 // disconnects foo, but not bar
760 sig.disconnect(&amp;foo);
761 </programlisting>
762 </entry>
763             </row>
764           </tbody>
765         </tgroup>
766       </informaltable>
767
768 </section>
769
770 <section><title>Automatic connection management (Intermediate)</title>
771 <para>Boost.Signals can automatically track the lifetime of objects
772 involved in signal/slot connections, including automatic
773 disconnection of slots when objects involved in the slot call are
774 destroyed. For instance, consider a simple news delivery service,
775 where clients connect to a news provider that then sends news to
776 all connected clients as information arrives. The news delivery
777 service may be constructed like this: </para>
778   <informaltable>
779     <tgroup cols="2" align="left">
780       <thead>
781         <row>
782           <entry>Preferred syntax</entry>
783           <entry>Portable syntax</entry>
784         </row>
785       </thead>
786       <tbody>
787         <row>
788           <entry>
789 <programlisting>
790 class NewsItem { /* ... */ };
791
792 boost::signal&lt;void (const NewsItem&amp;)&gt; deliverNews;
793 </programlisting>
794 </entry>
795 <entry>
796 <programlisting>
797 class NewsItem { /* ... */ };
798
799 boost::signal1&lt;void, const NewsItem&amp;&gt; deliverNews;
800 </programlisting>
801 </entry>
802             </row>
803           </tbody>
804         </tgroup>
805       </informaltable>
806
807 <para>Clients that wish to receive news updates need only connect a
808 function object that can receive news items to the
809 <code>deliverNews</code> signal. For instance, we may have a
810 special message area in our application specifically for news,
811 e.g.,:</para>
812 <programlisting>
813 struct NewsMessageArea : public MessageArea
814 {
815 public:
816   // ...
817
818   void displayNews(const NewsItem&amp; news) const
819   {
820     messageText = news.text();
821     update();
822   }
823 };
824
825 // ...
826 NewsMessageArea newsMessageArea = new NewsMessageArea(/* ... */);
827 // ...
828 deliverNews.<methodname>connect</methodname>(boost::bind(&amp;NewsMessageArea::displayNews, 
829                                 newsMessageArea, _1));
830 </programlisting>
831 <para>However, what if the user closes the news message area,
832 destroying the <code>newsMessageArea</code> object that
833 <code>deliverNews</code> knows about? Most likely, a segmentation
834 fault will occur. However, with Boost.Signals one need only make
835 <code>NewsMessageArea</code> <emphasis>trackable</emphasis>, and the slot
836 involving <code>newsMessageArea</code> will be disconnected when
837 <code>newsMessageArea</code> is destroyed. The
838 <code>NewsMessageArea</code> class is made trackable by deriving
839 publicly from the <code>boost::signals::trackable</code> class,
840 e.g.:</para>
841 <programlisting>
842 struct NewsMessageArea : public MessageArea, public boost::signals::trackable
843 {
844   // ...
845 };
846 </programlisting>
847 <para>At this time there is a significant limitation to the use of
848 <code>trackable</code> objects in making slot connections: function
849 objects built using Boost.Bind are understood, such that pointers
850 or references to <code>trackable</code> objects passed to
851 <code>boost::bind</code> will be found and tracked.</para>
852 <para><emphasis role="bold">Warning</emphasis>: User-defined function objects and function
853 objects from other libraries (e.g., Boost.Function or Boost.Lambda)
854 do not implement the required interfaces for <code>trackable</code>
855 object detection, and <emphasis>will silently ignore any bound trackable
856 objects</emphasis>. Future versions of the Boost libraries will address
857 this limitation.</para>
858 </section>
859
860 <section><title>When can disconnections occur? (Intermediate)</title>
861 <para>Signal/slot disconnections occur when any of these conditions
862 occur:</para>
863 <itemizedlist>
864 <listitem><para>The connection is explicitly disconnected via the connection's
865 <code>disconnect</code> method directly, or indirectly via the
866 signal's <code>disconnect</code> method or
867 <code>scoped_connection</code>'s destructor.</para></listitem>
868 <listitem><para>A <code>trackable</code> object bound to the slot is
869 destroyed.</para></listitem>
870 <listitem><para>The signal is destroyed.</para></listitem></itemizedlist>
871 <para>These events can occur at any time without disrupting a signal's
872 calling sequence. If a signal/slot connection is disconnected at
873 any time during a signal's calling sequence, the calling sequence
874 will still continue but will not invoke the disconnected slot.
875 Additionally, a signal may be destroyed while it is in a calling
876 sequence, and which case it will complete its slot call sequence
877 but may not be accessed directly.</para>
878 <para>Signals may be invoked recursively (e.g., a signal A calls a
879 slot B that invokes signal A...). The disconnection behavior does
880 not change in the recursive case, except that the slot calling
881 sequence includes slot calls for all nested invocations of the
882 signal.</para>
883 </section>
884
885 <section><title>Passing slots (Intermediate)</title>
886 <para>Slots in the Boost.Signals library are created from arbitrary
887 function objects, and therefore have no fixed type. However, it is
888 commonplace to require that slots be passed through interfaces that
889 cannot be templates. Slots can be passed via the
890 <code>slot_type</code> for each particular signal type and any
891 function object compatible with the signature of the signal can be
892 passed to a <code>slot_type</code> parameter. For instance:</para>
893   <informaltable>
894     <tgroup cols="2" align="left">
895       <thead>
896         <row>
897           <entry>Preferred syntax</entry>
898           <entry>Portable syntax</entry>
899         </row>
900       </thead>
901       <tbody>
902         <row>
903           <entry>
904 <programlisting>
905 class Button 
906 {
907   typedef boost::signal&lt;void (int x, int y)&gt; OnClick;
908
909 public:
910   void doOnClick(const OnClick::slot_type&amp; slot);
911
912 private:
913   OnClick onClick;
914 };
915
916 void Button::doOnClick(
917       const OnClick::slot_type&amp; slot
918     )
919 {
920   onClick.<methodname>connect</methodname>(slot);
921 }
922
923 void printCoordinates(long x, long y)
924 {
925   std::cout &lt;&lt; "(" &lt;&lt; x &lt;&lt; ", " &lt;&lt; y &lt;&lt; ")\n";
926 }
927
928 void f(Button&amp; button)
929 {
930   button.doOnClick(&amp;printCoordinates);
931 }
932 </programlisting>
933 </entry>
934 <entry>
935 <programlisting>
936 class Button 
937 {
938   typedef <classname alt="boost::signalN">boost::signal2</classname>&lt;void,int,int&gt; OnClick;
939
940 public:
941   void doOnClick(const OnClick::slot_type&amp; slot);
942
943 private:
944   OnClick onClick;
945 };
946
947 void Button::doOnClick(
948       const OnClick::slot_type&amp; slot
949     )
950 {
951   onClick.<methodname>connect</methodname>(slot);
952 }
953
954 void printCoordinates(long x, long y)
955 {
956   std::cout &lt;&lt; "(" &lt;&lt; x &lt;&lt; ", " &lt;&lt; y &lt;&lt; ")\n";
957 }
958
959 void f(Button&amp; button)
960 {
961   button.doOnClick(&amp;printCoordinates);
962 }
963 </programlisting>
964 </entry>
965             </row>
966           </tbody>
967         </tgroup>
968       </informaltable>
969
970 <para>The <code>doOnClick</code> method is now functionally equivalent
971 to the <code>connect</code> method of the <code>onClick</code>
972 signal, but the details of the <code>doOnClick</code> method can be
973 hidden in an implementation detail file.</para>
974 </section>
975 </section>
976
977 <section>
978   <title>Example: Document-View</title>
979   
980   <para>Signals can be used to implement flexible Document-View
981   architectures. The document will contain a signal to which each of
982   the views can connect. The following <code>Document</code> class
983   defines a simple text document that supports mulitple views. Note
984   that it stores a single signal to which all of the views will be
985   connected.</para>
986
987   <programlisting>class Document
988 {
989 public:
990     typedef boost::signal&lt;void (bool)&gt;  signal_t;
991     typedef boost::signals::connection  connection_t;
992
993 public:
994     Document()
995     {}
996
997     connection_t connect(signal_t::slot_function_type subscriber)
998     {
999         return m_sig.connect(subscriber);
1000     }
1001
1002     void disconnect(connection_t subscriber)
1003     {
1004         subscriber.disconnect();
1005     }
1006
1007     void append(const char* s)
1008     {
1009         m_text += s;
1010         m_sig(true);
1011     }
1012
1013     const std::string&amp; getText() const
1014     {
1015         return m_text;
1016     }
1017
1018 private:
1019     signal_t    m_sig;
1020     std::string m_text;
1021 };</programlisting>
1022
1023   <para>Next, we can define a <code>View</code> base class from which
1024   views can derive. This isn't strictly required, but it keeps the
1025   Document-View logic separate from the logic itself. Note that the
1026   constructor just connects the view to the document and the
1027   destructor disconnects the view.</para>
1028
1029   <programlisting>
1030 class View
1031 {
1032 public:
1033     View(Document&amp; m)
1034         : m_document(m)
1035     {
1036         m_connection = m_document.connect(boost::bind(&amp;View::refresh, this, _1));
1037     }
1038
1039     virtual ~View()
1040     {
1041         m_document.disconnect(m_connection);
1042     }
1043
1044     virtual void refresh(bool bExtended) const = 0;
1045
1046 protected:
1047     Document&amp;               m_document;
1048
1049 private:
1050     Document::connection_t  m_connection;
1051 };
1052   </programlisting>
1053
1054   <para>Finally, we can begin to define views. The
1055   following <code>TextView</code> class provides a simple view of the
1056     document text.</para>
1057
1058   <programlisting>class TextView : public View
1059 {
1060 public:
1061     TextView(Document&amp; doc)
1062         : View(doc)
1063     {}
1064
1065     virtual void refresh(bool bExtended) const
1066     {
1067         std::cout &lt;&lt; "TextView: " &lt;&lt; m_document.getText() &lt;&lt; std::endl;
1068     }
1069 };</programlisting>
1070
1071   <para>Alternatively, we can provide a view of the document
1072     translated into hex values using the <code>HexView</code>
1073     view:</para>
1074
1075   <programlisting>class HexView : public View
1076 {
1077 public:
1078     HexView(Document&amp; doc)
1079         : View(doc)
1080     {}
1081
1082     virtual void refresh(bool bExtended) const
1083     {
1084         const std::string&amp;  s = m_document.getText();
1085
1086         std::cout &lt;&lt; "HexView:";
1087
1088         for (std::string::const_iterator it = s.begin(); it != s.end(); ++it)
1089             std::cout &lt;&lt; ' ' &lt;&lt; std::hex &lt;&lt; static_cast&lt;int&gt;(*it);
1090
1091         std::cout &lt;&lt; std::endl;
1092     }
1093 };</programlisting>
1094
1095   <para>To tie the example together, here is a
1096   simple <code>main</code> function that sets up two views and then
1097     modifies the document:</para>
1098
1099   <programlisting>int main(int argc, char* argv[])
1100 {
1101     Document    doc;
1102     TextView    v1(doc);
1103     HexView     v2(doc);
1104
1105     doc.append(argc == 2 ? argv[1] : "Hello world!");
1106     return 0;
1107 }</programlisting>
1108
1109   <para>The complete example source, contributed by Keith MacDonald,
1110     is available in <ulink
1111     url="../../libs/signals/example/doc_view.cpp"><code>libs/signals/example/doc_view.cpp</code></ulink>.</para>
1112 </section>
1113
1114 <section>
1115   <title>Linking against the Signals library</title>
1116
1117   <para>Part of the Boost.Signals library is compiled into a binary
1118   library that must be linked into your application to use
1119   Signals. Please refer to
1120     the <ulink url="../../more/getting_started.html">Getting Started</ulink>
1121   guide. You will need to link against the <code>boost_signals</code>
1122   library.</para>
1123 </section>
1124
1125 </section>