1. Edd Dawson
  2. sigfwd

Wiki

Clone wiki

sigfwd / usage

API tour and library usage

In order to create connections from Qt signals to regular C++ functions and functors, sigfwd provides two functions:

namespace sigfwd
{

    template<typename Functor>
    connection connect(QObject *emitter, const char *qt_signal_sig, const Functor &receiver, 
                       Qt::ConnectionType conn_type = Qt::AutoConnection, bool check_sigs = true);

    template<typename CallSig, typename Functor>
    connection connectx(QObject *emitter, const char *qt_signal_sig, const Functor &receiver, 
                        Qt::ConnectionType conn_type = Qt::AutoConnection, bool check_sigs = true);
}

Access these with a #include <sigfwd/connect.hpp>. Or you might include the <sigfwd/sigfwd.hpp> header instead, which makes available everything the library has to offer.

These functions essentially do the same thing, except that connect tries to deduce the call signature of the receiver argument automatically. Sometimes this isn't possible and so you'll need to call connectx instead and specify the signature:

sigfwd::connect(solve_action, SIGNAL(triggered()), solve_equation);

// if the signature of the solve_equation functor above cannot be deduced,
// connectx will have to be used instead:

sigfwd::connectx<void ()>(solve_action, SIGNAL(triggered()), solve_equation);

To find out more about which types of functor are supported out the box, take a look at the page on supported functors.

The conn_type argument allows you to specify the type of connection that will be created. See the Qt documentation for more on that.

The last argument, check_sigs determines whether or not a comparison is made between the signature of the Qt signal given by qt_signal_sig and that of receiver (or CallSig in the case of connectx usage).

It is strongly recommended that you set this to true (the default). However, under some (rare) circumstances, the signal checking functionality might get confused and you'll have to by-pass it. In this case, the responsibility of checking the compatibility of those signatures rests entirely on your shoulers. If you get it wrong, your program will probably crash, or worse...

To find out more about when the built-in signature checking might get confused, take a look at the wiki page on signature compatibility testing.

Note however, that sigfwd's signature checking is always conservative, meaning that even though it may occasionally fail to see that two signatures are compatible, it will never create a connection when signatures are incompatible.

The sigfwd::connection object returned by connect and connectx allows you to determine whether or not the connection was made successfully.

sigfwd::connection has an implicit conversion to a type that evaluates to true or false in boolean contexts. In other words, you can write code like this to quickly check if the connection was made sucessfully:

if (!sigfwd::connect(solve_action, SIGNAL(triggered()), solve_equation))
{
   // oh dear, connection failed
}

If the connection attempt failed, the connection object has a status member which contains an enumeration constant:

namespace sigfwd
{
    enum result 
    { 
        connected = 0,           //!< a signal was connected successfully
        sigs_incompatible = -1,  //!< a signal couldn't be connected due to a call signature incompatibility
        signal_not_found = -2    //!< the signal couldn't be found in the emitter QObject
    };

    struct connection
    {   
        // ...

        result status; //!< The status of the connection.
    };

}

Disconnection

The sigfwd::connection object returned by connect and connectx also contains a QObject* called qobj. If the connection attempt succeeded, then this pointer will be non-null-valued. delete-ing it will disconnect the object:

sigfwd::connection c = sigfwd::connect(solve_action, SIGNAL(triggered()), solve_equation);

// ...

delete c.qobj;
c.qobj = 0;

The parent of qobj is the signal emitter. So if the emitter is deleted, disconnection happens automatically.

Copying vs referencing functors

By default connect and connectx will make a copy of the receiver you specify. If you would like to use an uncopyable functor, or want to prevent a copy for some other reason, you can use boost::ref or boost::cref to wrap your functor:

sigfwd::connect(widget, SIGNAL(clicked()), boost::ref(big_functor));

Updated