boost.png (6897 bytes) Home Libraries People FAQ More

PrevUpHomeNext

Design Overview

Type Erasure
connection class
Slot Call Iterator
visit_each function template

Type Erasure

"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).

connection class

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).

Slot Call Iterator

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 value_type of this iterator will be std::pair<any, connection>, where the any contains an instance of the slot function type.

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 boost::any object that holds the slot function).

Transform Iterator Adaptor

This transform iterator adaptor performs an any_cast to extract a reference to the slot function with the appropriate slot function type.

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.

visit_each function template

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.

Last revised: March 12, 2003 at 23:27:22 GMT

Copyright © 2001-2004 Douglas Gregor

PrevUpHomeNext