QObject::connect: Cannot queue arguments of type MyClass*const
Asked Answered
E

2

8

I have such class:

#include <QObject>
namespace taservices
{
    class ProcessHandle : public QObject
    {
        Q_OBJECT
    public:
        ProcessHandle(const void* const processContextPointer, const QString& process_id = "", QObject *parent = 0);
        ProcessHandle();
    signals:
        void progress(const ProcessHandle* const self, const int value);
    private:
        static void registerAsMetaType();
}

I have a signal:

void progress(const ProcessHandle* const self, const int value);

I want to connect it through QueuedConnedtion. I keep getting this message:

QObject::connect: Cannot queue arguments of type 'ProcessHandle*const'
(Make sure 'ProcessHandle*const' is registered using qRegisterMetaType().)

I register my class like this after it's declaration:

Q_DECLARE_METATYPE(taservices::ProcessHandle*);

I also added this static method which I call from constructor:

void ProcessHandle::registerAsMetaType()
{
    static bool called = false;
    if(!called) {
        called = true;
        qRegisterMetaType<ProcessHandle*>("taservices::ProcessHandle*");
    }
}

I tried to register const pointer as well:

qRegisterMetaType<ProcessHandle*const>("taservices::ProcessHandle*const");

It causes following error:

error C2440: 'return' : cannot convert from 'taservices::ProcessHandle *const *' to 'void *'

So how do I make my class work with Queued connections?

Edme answered 10/2, 2017 at 15:43 Comment(0)
H
3

There's no point whatsoever to signals with const value parameters. The only point of constness would be to prevent the implementation from misbehaving and modifying the value, with the implication that somehow the value should not be modified (why not? it's an implementation detail that you leak into the interface!). The signal's code is generated by moc, and if such code were to misbehave you've got way bigger problems already.

Your signal should have the following declaration:

Q_SIGNAL void progress(const ProcessHandle* self, int value);

The slot is free to have const arguments. Innermost constness is not a part of the signature as far as Qt is concerned - it is effectively stripped out.

You don't need to register the types. It's done automatically when you let connect access the type by using the new connect syntax.

Example:

// https://github.com/KubaO/stackoverflown/tree/master/questions/const-slot-arg-42163294
#include <QtCore>

struct ProcessHandle {};

struct Object : QObject {
    int counter = 0;
    Q_SIGNAL void newValue(const ProcessHandle*, int val);
    Q_SLOT void useValue(const ProcessHandle* const ph, const int val) {
        qDebug() << ph << val;
        Q_ASSERT(ph == nullptr && val == 42);
        ++counter;
    }
    Q_OBJECT
};

int main(int argc, char ** argv) {
    QCoreApplication app{argc, argv};
    Object obj;
    QObject::connect(&obj, &Object::newValue, &obj, &Object::useValue, Qt::QueuedConnection);
    QObject::connect(&obj, &Object::newValue, &app, &QCoreApplication::quit, Qt::QueuedConnection);
    emit obj.newValue(nullptr, 42);
    app.exec();
    Q_ASSERT(obj.counter == 1);
}

#include "main.moc"
Hunkydory answered 10/2, 2017 at 16:12 Comment(1)
The intention is to keep the pointer argument in target slots const, since you should not change it to different address.Ondrea
E
8

Turns out this is what you need:

qRegisterMetaType<ProcessHandle*>("ProcessHandle*");
qRegisterMetaType<ProcessHandle*>("ProcessHandle*const");

For the purposes of queuing arguments, const pointer is equal to normal pointer, since it's being copied not changed.

Edme answered 10/2, 2017 at 16:5 Comment(0)
H
3

There's no point whatsoever to signals with const value parameters. The only point of constness would be to prevent the implementation from misbehaving and modifying the value, with the implication that somehow the value should not be modified (why not? it's an implementation detail that you leak into the interface!). The signal's code is generated by moc, and if such code were to misbehave you've got way bigger problems already.

Your signal should have the following declaration:

Q_SIGNAL void progress(const ProcessHandle* self, int value);

The slot is free to have const arguments. Innermost constness is not a part of the signature as far as Qt is concerned - it is effectively stripped out.

You don't need to register the types. It's done automatically when you let connect access the type by using the new connect syntax.

Example:

// https://github.com/KubaO/stackoverflown/tree/master/questions/const-slot-arg-42163294
#include <QtCore>

struct ProcessHandle {};

struct Object : QObject {
    int counter = 0;
    Q_SIGNAL void newValue(const ProcessHandle*, int val);
    Q_SLOT void useValue(const ProcessHandle* const ph, const int val) {
        qDebug() << ph << val;
        Q_ASSERT(ph == nullptr && val == 42);
        ++counter;
    }
    Q_OBJECT
};

int main(int argc, char ** argv) {
    QCoreApplication app{argc, argv};
    Object obj;
    QObject::connect(&obj, &Object::newValue, &obj, &Object::useValue, Qt::QueuedConnection);
    QObject::connect(&obj, &Object::newValue, &app, &QCoreApplication::quit, Qt::QueuedConnection);
    emit obj.newValue(nullptr, 42);
    app.exec();
    Q_ASSERT(obj.counter == 1);
}

#include "main.moc"
Hunkydory answered 10/2, 2017 at 16:12 Comment(1)
The intention is to keep the pointer argument in target slots const, since you should not change it to different address.Ondrea

© 2022 - 2024 — McMap. All rights reserved.