QT5 Signals and slots over a network

In a recent project, we wanted to be able to call QT5 signals/slots from a network connection, for unit testing and for communicating with other parts of the system that are written in other languages. After spending way too much time in duck typed dynamic languages like Python and Javascript, I naively thought this would be pretty easy given the introspection abilities of c++11 and  Qt’s MOC. I was wrong. Below is a solution that involves about 48 straight hours of tinkering and coding over a weekend, all why saying “This should be so easy. I’m an idiot, and must be missing something obvious.”


Before I jump in to the code, I want to point out that I did *not* use c++11 variadic templates for this, even though this problem totally screams “USE VARIADIC TEMPLATES”. That was because after a full weekend with maybe 4 hours of sleep total, just manually brute forcing a solution for < 9 arguments was sufficient for my needs.  I’ll leave it as an exercise for the reader to take this and make it work with a variadic template solution. If you do, be sure to let me know.

The Use Case:

We have JSON messages coming in over a QWebSocket with information on which signal/slot to call like this: ‘{“obj”: “obj_id”, “name”:”slot_name”, “args”: { “foo”: 1, “bar”: “hello world” }}’. I want to call the Qt Signal names ‘slot_name’ on the object with the unique id obj_id, and with the values foo=1, bar =”hello world”. (basically I want to do a call like: obj_list[obj_id]->slot_name(1,  “hello world”); ) This is great for integration testing, causing weird faults, testing pieces of code that are only triggered by signals, and just in general integrating our Qt Application with the rest of our system that communicates over Websockets with JSON.

The straightforward part:

We can already figure out type information for the arguments (e.g. foo is an int, bar is a QString) from Qt’s MetaObject / MetaMethod system and return an error code to the remote caller if the argument value can’t be coerced into the appropriate type. The actual coercing can be done with QVariant’s value() template function.  Tweet me if you want a write-up of how I did that, but It’s pretty straight forward with a look at the Qt documentation.

Alright, so now I have a  this QJsonArray of values, I know their types, and can coerce them at will using a combination of QMetaMethod’s type list and QVariant’s value(). How do I actually call the signal/slot ? The problem is that any  type coercion for a function has to be known at compile time.


The harder part:

This solution will take a  list of QVariants (QVariantList) of unknown types, coerce them into the correct types for the method arguments, and then call the methods with the values. The only caveat is that this method will not work with reference arguments (e.g. int &foo).

Alright, so there are two parts to this: macro magic, and template magic.


Macro magic:

All this template does is define a method names __COERCE_func_name , constructs a Coercer with the signature of CLASS::func_name, and then call the templated coercer object’s coerce method with a point to the appropriate function pointer and argument variant list.


Template magic:

This is where the coercion actually happens. I’ve only included  0 and 1 arguments templates for brevity, but I also manually copy and pasted 2-9 argument versions.  The hard part was figuring out this syntax:

This takes a method pointer from the class Obj, that takes a single argument, and returns type R. Now that we have the types of the arguments we can call QVariant.value<Arg>() to turn the QVariant into the correct value, and call the function with it!


There you go. That’s how you can call slots,  with arguments, over a Websocket. All you need to do is ‘register’ your slot like below, and the rest is handled auto-magically by the template

Easy huh?



Next Steps: Do it in pure C++11


Leave a Reply