QObject::connect: Cannot queue arguments of type 'int&'
Asked Answered
J

2

18

I tried to do this :

connect(this, SIGNAL(signalClicked(int&)),  classA, SLOT(doWork(int&)));

But I get the message in the title. So I've explored the internet and I came up with this solution which is not working either:

 qRegisterMetaType<int&>("Type");
 connect(this, SIGNAL(signalClicked(Type)),  classA, SLOT(doWork(Type)));

Error: no matching function for call to ‘qRegisterMetaType(const char[5])’

Any solutions?

Junco answered 13/6, 2013 at 9:15 Comment(7)
Do you #include <QMetaType>?Dermot
Yes I do, that's why I don't get it...Junco
Thanks for your answer but I have already found this solution here qtforum.org/article/36440/… and unfortunately it's still not working.Junco
Where's your Q_DECLARE_METATYPE ?Dehydrate
Just under the includes.Junco
According to the Qt docs for qRegisterMetaType "Any class or struct that has a public default constructor, a public copy constructor, and a public destructor can be registered.", which suggests it is only for classes and structs. Someone may be able to correct me here, but I don't think you should be needing to register the type int&.Ally
That's exactly what I thought.Junco
K
29

If Qt is trying to queue the arguments that means that the connection is between threads. This will not work for non-const references.

You could use a reference_wrapper to work around this, but I would strongly suggest that you reconsider your design. Passing values by reference in signal/slot connections is not a good idea.

Kerosene answered 13/6, 2013 at 9:34 Comment(5)
I know it is not the good way to do it but I am new to this and that is the only solution I found. Actually what I'm trying to achieve is to update an attribute in the main thread and read it from another thread in an infinite loop. I'll try what you've suggested thoughJunco
@Dan-Milburn, as Qt copies the object, why is not a good idea to pass values by reference?Ally
If Qt takes a copy, what is the point in passing by (non-const) reference? The receiving slot would not be able to modify the original anyway (while being mislead into thinking that it could). Further, the point behind Qt signals/slots is that the signal emitter does not know what is connected to it, or how many connections there are. If there are two connected slots, and they both try to modify the object that was passed by reference then you have all sorts of potential for bugs. It will work, in limited situations, with non-queued connections, but it's still bad design.Kerosene
@Junco You could just emit a signal in the main that passes the value as an argument to a slot in your thread every time you change the value of that variable. Also note, that you can't pass a non-const reference as an argument in signals and slots when using a queued connection.Indigotin
@DanMilburn, I see your point about the misleading declaration. If it were desired to pass by reference, use of QMutex to prevent issues from multiple listeners modifying the data would protect from problems. This, however is academic because in QMetaObject::activate, if the connection type is AutoConnection and sender and receiver are in different threads, the value gets copied. See here: woboq.com/blog/how-qt-signals-slots-work.htmlAlly
M
1

I wanted to be able to connect an event with an std::shared_ptr<>. What I have done is create a structure with that pointer and the structure is what I declare and use to send the event.

So I have an object like so:

class project
{
    typedef std::shared_ptr<project> pointer_t;

    ...
};

I need to call the Q_DECLARE_METATYPE() to pass the smart pointer. So my first idea:

Q_DECLARE_METATYPE(builder::project::pointer_t)

That did not work at all. So instead what I had to do is create a structure with that pointer and created that outside of the namespace (builder above):

// outside my namespace
struct project_ptr
{
    builder::project::pointer_t f_ptr = builder::project::pointer_t();

private:
    Q_GADGET
};

Q_DECLARE_METATYPE(project_ptr);

Then in my main class (a QWindow) I have a function to emit the signal, the actual signal, and a slot to process the message:

class snap_builder
    : public QMainWindow
    , private Ui::snap_builder
{
private:
    Q_OBJECT

public:
    ...
    void     project_changed(project::pointer_t p);

signals:
    void     projectChanged(project_ptr p);

private slots:
    void     onProjectChanged(project_ptr p);
    ...
};

As we can see, the class can include anything you want (pretty much) but the type is used by copy (no reference, no pointer).

To emit the event, I then call the project_changed() function which creates a project_ptr with the project pointer and sends that using the emit ... feature of Qt.

void snap_builder::project_changed(project::pointer_t p)
{
    project_ptr ptr;
    ptr.f_ptr = p;
    emit projectChanged(ptr);
}

Finally, you have to connect that event like so, which I do in my constructor:

connect(this, &snap_builder::projectChanged,
        this, &snap_builder::on_project_changed);

I find it rather convoluted, but that works as expected.

Meister answered 11/11, 2023 at 6:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.