The components in the Dataflow.Signals layer are implemented using Boost.Fusion. To use the components, you don't need to know anything about Boost.Fusion, but for some advanced uses you might benefit from taking advantage of the fact that Boost.Fusion is under the hood.

If you're not familiar with fusion, here are a few basic concepts you might find helpful in the context of Dataflow.Signals:

Fused vs. unfused

A simple C++ function object might look something like this:

struct f
{
    int operator()(int arg1, int &arg2, const std::string &arg3)
    {
        ...
    }
}

The thing to note here is that there are three arguments (of types int, int &, and const std::string & respectively), and that when the function object is invoked, they are passed separately:

int x;
std::string s;
f()(1, x, s);

In the terminology of Boost.Fusion, this function object is unfused. This is in contrast to a fused fuction object, which might look like this:

struct fused_f
{
    int operator()(fusion::vector<int, int &, const std::string &> &args)
    {
        ...
    }
}

Basically, the difference is that the three arguments from the unfused version are now sent in a single fusion container. The benefit is that no matter how many "unfused" arguments there are, there is always a single "fused" argument. Hence, writing templates that deal with a variable number of arguments becomes a lot simpler.

Dataflow.Signals provides both fused and unfused components

While writing the generic components provided in the Dataflow.Signals module benefits from using Boost.Fusion, your particular use case might not. For this reason, every component provided by the Dataflow.Signals module:

  • can receive both fused and unfused signals
  • has both a version that sends fused signals and a version that sends unfused signals.

The type of sent signal is provided as a template argument to the class, with the default value being unfused.

For example,

signals::storage<int (int, int &, const std::string &>), signals::unfused> unfused_storage;
signals::storage<int (int, int &, const std::string &>)> unfused_storage_by_default;
signals::storage<int (int, int &, const std::string &>), signals::output::fused> fused_storage;

In the above case, unfused_storage is similar to f above, and can be used as a slot for signals which carry regular, unfused arguments. On the other hand, fused_storage acts as a function object similar to fused_f above. Hence, it can be used as a slot for signals which carry a fusion container as an argument.

Examples mostly show unfused versions

The examples shown in this documentation are mostly focused on the unfused versions of the components, since a user starting with the library is most likely to be using the library with unfused components. In the vast majority of cases, when all of the components used are library-provided components, the fused and unfused examples are identical except for the specifications that the components should be fused or unfused.