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< 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><void (float, 153float)></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<float (float, float)> 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<float></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><float (float x, float y), 208 maximum<float> > 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><float (float, float), 228 aggregate_values<std::vector<float> > > 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<typename InputIterator> 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><void ()> 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<void (const NewsItem&)> 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& news) const 383 { 384 messageText = news.text(); 385 update(); 386 } 387}; 388 389// ... 390NewsMessageArea *newsMessageArea = new NewsMessageArea(/* ... */); 391// ... 392deliverNews.<methodname>connect</methodname>(boost::bind(&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<NewsMessageArea> newsMessageArea(new NewsMessageArea(/* ... */)); 413// ... 414deliverNews.<methodname>connect</methodname>(signal_type::slot_type(&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<void (int), mutex_type<bs2::dummy_mutex> >::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