in Code

QSignalMapper Example Revisited

Qt Library

Qt Library

Several years ago I wrote a short piece on QSignalMapper to give a quick example of how it can be used. Since then, Qt5 has been released and C++11 is now A Thing.

One of the cool things introduced in Qt5 is a new overload for the QObject::connect() method:

This means we can use function pointers instead of the old (char *) based method. One of the big advantages of using the new method is that it can check signal/slot connections at compile-time instead of only at run-time. If the signature of either the sender or receiver changes the code will fail to compile. (If you are using C++11 and like to write “clever” code, you can now use lambda expressions as well!) There’s a decent overview of the new method in this blog post by Olivier Goffart.

I recently started updating my aging codebase to Qt5 and C++11 and one of the things I’m changing is all my connections to use the new format. I ran into an issue almost immediately that I thought I’d document in case I can save someone some time.

If we look at the example from my previous article on QSignalMapper:

the changes to the new connect format seem like they should be really straightforward:

But try to compile it and we have a problem:

So what’s going on here? The problem is that QSignalMapper::map is overloaded and the compiler doesn’t know which one to choose:

The solution is to cast the function pointer to the one we want like so:

Likewise, the final connect() in that function has a problem because QSignalMapper::mapped has four overloads. This can be solved by casting the function pointer like this:

So our final code for this function looks like this:

This is perhaps a bit uglier than the original code, but it does have advantages as mentioned earlier. In practice, I’ve found that, for my code, most of the connect() conversions to the new format don’t require any casting, so it cleans things up nicely and gives me better compile-time error reporting.

Hope that helps!

Write a Comment

Comment

  1. There is a typo in your updated connect code. The second paragraph refers to the website object twice where it should have been forums.

      • No prob. Also typo here:

        QAction *website = new QAction( tr( “Website” ), this );
        signalMapper->setMapping( website, “http://example.com” );
        connect( action, &QAction::triggered,
        signalMapper, static_cast(&QSignalMapper::map) );
        helpMenu->addAction( website );

        QAction *forums = new QAction( tr( “Support Forums Online” ), this );
        signalMapper->setMapping( forums, “http://example.com/forum/” );
        connect( action, &QAction::triggered,
        signalMapper, static_cast(&QSignalMapper::map) );
        helpMenu->addAction( forums );

    • If I understand your question properly, then yes. One of the prototypes of the setMapping() function is this:

      setMapping(QObject *sender, QObject *object)

      Depending on your use-case and Qt version, you might want to look at using lambdas instead. I’ve eliminated the use of QSignalMapper in my code using them and it cleaned everything up.

      I wrote a bit about using lambdas with Qt in Using C++11 Lambdas As Qt Slots.