|  | Home | Libraries | People | FAQ | More | 
"Type erasure", where static type information is eliminated
    by the use of dynamically dispatched interfaces, is used
    extensively within the Boost.Signals library to reduce the amount
    of code generated by template instantiation. Each signal must
    manage a list of slots and their associated connections, along
    with a std::map to map from group identifiers to
    their associated connections. However, instantiating this map for
    every token type, and perhaps within each translation unit (for
    some popular template instantiation strategies) increase compile
    time overhead and space overhead.
 To combat this so-called "template bloat", we use
    Boost.Function and Boost.Any to store unknown types and
    operations. Then, all of the code for handling the list of slots
    and the mapping from slot identifiers to connections is factored
    into the class signal_base
    that deals exclusively with the any and
    function objects, hiding the
    actual implementations using the well-known pimpl idiom. The
    actual signalN class templates
    deal only with code that will change depending on the number of
    arguments or which is inherently template-dependent (such as
    connection).
 The connection class is
    central to the behavior of the Boost.Signals library. It is the
    only entity within the Boost.Signals system that has knowledge of
    all objects that are associated by a given connection. To be
    specific, the connection class
    itself is merely a thin wrapper over a
    shared_ptr to a
    basic_connection object.
 connection objects are
    stored by all participants in the Signals system: each
    trackable object contains a
    list of connection objects
    describing all connections it is a part of; similarly, all signals
    contain a set of pairs that define a slot. The pairs consist of a
    slot function object (generally a Boost.Function object) and a
    connection object (that will
    disconnect on destruction). Finally, the mapping from slot groups
    to slots is based on the key value in a
    std::multimap (the stored data
    in the std::multimap is the
    slot pair).
The slot call iterator is conceptually a stack of iterator adaptors that modify the behavior of the underlying iterator through the list of slots. The following table describes the type and behavior of each iterator adaptor required. Note that this is only a conceptual model: the implementation collapses all these layers into a single iterator adaptor because several popular compilers failed to compile the implementation of the conceptual model.
| Iterator Adaptor | Purpose | 
|---|---|
| Slot List Iterator | An iterator through the list of slots
            connected to a signal. The  | 
| Filter Iterator Adaptor | This filtering iterator adaptor filters out slots that have been disconnected, so we never see a disconnected slot in later stages. | 
| Projection Iterator Adaptor | The projection iterator adaptor returns a
            reference to the first member of the pair that constitutes
            a connected slot (e.g., just the
             | 
| Transform Iterator Adaptor | This transform iterator adaptor performs an
             | 
| Transform Iterator Adaptor | This transform iterator adaptor calls the function object returned by dereferencing the underlying iterator with the set of arguments given to the signal itself, and returns the result of that slot call. | 
| Input Caching Iterator Adaptor | This iterator adaptor caches the result of dereferencing the underlying iterator. Therefore, dereferencing this iterator multiple times will only result in the underlying iterator being dereferenced once; thus, a slot can only be called once but its result can be used multiple times. | 
| Slot Call Iterator | Iterates over calls to each slot. | 
 The visit_each
    function template is a mechanism for discovering objects that are
    stored within another object. Function template
    visit_each takes three
    arguments: an object to explore, a visitor function object that is
    invoked with each subobject, and the int 0. 
 The third parameter is merely a temporary solution to the
    widespread lack of proper function template partial ordering. The
    primary visit_each
    function template specifies this third parameter type to be
    long, whereas any user specializations must specify
    their third parameter to be of type int. Thus, even
    though a broken compiler cannot tell the ordering between, e.g., a
    match against a parameter T and a parameter
    A<T>, it can determine that the conversion from
    the integer 0 to int is better than the conversion to
    long. The ordering determined by this conversion thus
    achieves partial ordering of the function templates in a limited,
    but successful, way. The following example illustrates the use of
    this technique:
template<typename> class A {};
template<typename T> void foo(T, long);
template<typename T> void foo(A<T>, int);
A<T> at;
foo(at, 0);
 In this example, we assume that our compiler can not tell
    that A<T> is a better match than
    T, and therefore assume that the function templates
    cannot be ordered based on that parameter. Then the conversion
    from 0 to int is better than the conversion from 0 to
    long, and the second function template is
    chosen.