Boost logo

Boost :

From: Beman Dawes (bdawes_at_[hidden])
Date: 2001-11-21 21:07:35


Nice explanation, rationale, and comparison to libsigc++!

Please add this to your docs. The C++ committee is very interested in both
rationale for design decisions, and comparisons to other libraries. So
even if it is just a copy of your raw message below, please to add it.

I think I'm going to start encouraging Boost developers to add a (possibly
empty) FAQ to docs right from the word go. That way there is a place to
put answers to questions as they come up.



At 06:50 PM 11/21/2001, Douglas Gregor wrote:
>On Wednesday 21 November 2001 04:48 am, you wrote:
>> I'm sorry for possible off-topic, but could you please comment how your
>> work is related to libsigc++?
>I can give you a comparison 'to the best of my knowledge.' I've looked at

>documentation and implementation of libsigc++ before, but have not used
>The libraries are quite similar on the surface - the connection and
>classes from each have nearly identical interfaces; the SigC::Object
>quite similar to the "bindable" class from Signals in that a user type
>derives from one of these classes to enable automatic connection lifetime

>management (which both libraries support).
>I'll try to describe the differences in greater detail:
>libsigc++ Marshallers vs. Signals Combiners
>Both of these entities perform the same function: when a signal calls
>multiple slots, there must be some way to take the return values of many
>slots and make it into a return value for the signal itself.
>The libsigc++ Marshaller interface looks like this:
> struct SomeMarshal
> {
> // both typedefs must be defined.
> typedef Type1 InType; // type returned by a slot
> typedef Type2 OutType; // type returned by the signal
> // Return final return code.
> OutType value();
> // Return value if marshaller does not get built
> static OutType default_value();
> // Captures return codes and returns TRUE to stop emittion.
> bool marshal(const InType&);
> SomeMarshal();
> };
>When a libsigc++ signal invokes its slots, it will essentially do this:
> Marshaller marshaller;
> while (slot = next_slot() && marshaller.marshal(slot(...)));
> return marshaller.value();
>The Signals Combiner interface looks like this:
>struct Combiner {
> typedef T result_type;
> template<typename InputIterator>
> T operator()(InputIterator first, InputIterator last) const;
>When a Signals signal invokes its slots, it will do this:
>Combiner combiner;
>return combiner(first, last);
>There is no difference in the power or flexibility afforded by either
>However, I'll claim that the approach taken by the Signals library is
>natural within the context of C++: the act of calling the slots is merely

>iteration through the input iterator sequence the combiner is given, and
>combiner itself is just a function object taking an input iterator range.

>Often, it's much easier to use an interface where you "pull" the data as
>want it: if you don't pull data from a slot, that slot won't be called,
>the equivalent of a libsigc++ marshaller returning "TRUE" from marshal()
>return statement in a Signals combiner.
>It is, of course, a matter of preference, but I believe that a function
>object taking an input iterator sequence and returning a value is more
>the spirit of C++" than defining a special interface for this same
>Argument Binding
>Both libraries "allow" argument binding, and arguments bound in creating
>slots can be tracked so that when they die, connections involving them
>removed. The difference between libsigc++ and Signals is mostly
>philosophical: libsigc++ includes limited capability for binding
>and can track objects bound in the manner. Signals, on the other hand,
>not do any argument binding. Instead, another binder library (e.g.,
>Boost.Bind or Lambda) will perform argument binding and there is a bound
>argument discovery interface used by Signals to find those arguments.
>This keeps Signals decoupled from binding, so as new binding libraries
>available Signals can adapt to them without any internal changes.
>doesn't currently have this ability.
>What's a Slot?
>Signals has a much looser definition of a slot than libsigc++ does.
>is relatively strict regarding what a slot is -- return and argument
>should match exactly with the signal, and if there is a difference one
>manually build an adaptor to the appropriate type.
>The Signals definition of a slot is the same as that of a target for
>Boost.Function -- anything such that parameters of the type taken by the
>signal can be passed to the slot, and the return value of the slot
>to the type expected by the signal. Thus all adaption is done internally
>without user intervention.
>I'll claim that the looser definition is more appropriate for a few
> - It's silly to manually adapt because the signal takes an std::string
>the slot takes a const std::string&.
> - Manual adaptations clutter the code (other side of the coin: they
>conversions explicit -- my side of the coin: they make trivial
>explicit, too)
> - Generic libraries define interfaces in terms of expressions, not
>So saying that we need a function object that takes two ints and returns
>float is uncommon: instead we say that we need the expression f(a, b) to
>convertible to a float when a, b are integers. Signals follows this
>programming view more closely.
>I hope such a comparison was useful, and if there are any other details
>libsigc++ for which information about the Signals equivalent could be
>helpful, please do ask.
> Doug
>Info: Unsubscribe:
>Your use of Yahoo! Groups is subject to

Boost list run by bdawes at, gregod at, cpdaniel at, john at