QObject::connect:无法排队类型为'int&'的参数

17

我试图做这件事:

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

但是我明白标题中的信息。因此我搜索了互联网并且想出了这个解决方案,但它也不起作用:

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

错误:没有匹配的函数可调用 'qRegisterMetaType(const char[5])'

有什么解决方案吗?


1
你是否#include <QMetaType> - Angew is no longer proud of SO
2
你的 Q_DECLARE_METATYPE 在哪里? - JBL
1
就在“includes”下方。 - Thibel
2
根据Qt文档中的qRegisterMetaType,“任何具有公共默认构造函数、公共复制构造函数和公共析构函数的类或结构体都可以被注册”,这表明它仅适用于类和结构体。也许有人能在这里纠正我,但我认为你不应该需要注册int&类型。 - TheDarkKnight
1
这正是我所想的。 - Thibel
显示剩余2条评论
2个回答

29
如果Qt试图将参数排队,那么这意味着连接处于不同的线程。对于非const引用,这种情况是行不通的。您可以使用reference_wrapper来解决此问题,但我强烈建议您重新考虑设计。在信号/槽连接中通过引用传递值并不是一个好主意。

我知道这不是一个好的做法,但我还是新手,这是我找到的唯一解决方案。实际上,我想要实现的是在主线程中更新属性,并在另一个线程中无限循环读取它。不过,我会尝试你建议的方法。 - Thibel
4
由于 Qt 会复制对象,为什么传递引用不是一个好主意? - TheDarkKnight
1
如果Qt进行复制,通过(非const)引用传递的意义何在?接收的槽位无法修改原始内容(同时会被误导以为可以)。此外,Qt信号/槽的重点是信号发射器不知道连接了什么,或有多少个连接。如果有两个连接的槽位,并且它们都试图修改按引用传递的对象,则可能产生各种各样的错误。在非排队连接的有限情况下,它可以工作,但这仍然是不良设计。 - Dan Milburn
2
@Thibel 你可以在主线程中发出一个信号,将该变量的值作为参数传递给线程中的槽函数,每次改变该变量的值时都这样做。另外请注意,在使用排队连接时,无法将非const引用作为信号和槽函数的参数传递。 - thuga
@DanMilburn,我理解你所说的误导性声明。如果想要通过引用传递,使用QMutex来防止多个监听器修改数据会保护免受问题的影响。然而,这是学术性的,因为在QMetaObject :: activate中,如果连接类型为AutoConnection并且发送者和接收者位于不同的线程中,则该值将被复制。请参见此处:http://woboq.com/blog/how-qt-signals-slots-work.html - TheDarkKnight

1
我想要能够将事件与一个std::shared_ptr<>连接起来。我所做的是创建一个包含该指针的结构体,并且这个结构体是我声明和用来发送事件的对象。
所以我有一个对象,像这样:
class project
{
    typedef std::shared_ptr<project> pointer_t;

    ...
};

我需要调用Q_DECLARE_METATYPE()来传递智能指针。所以我的第一个想法是:
Q_DECLARE_METATYPE(builder::project::pointer_t)

那根本没有起作用。所以我不得不创建一个带有指针的结构,并将其创建在命名空间之外(上面的builder)。
// outside my namespace
struct project_ptr
{
    builder::project::pointer_t f_ptr = builder::project::pointer_t();

private:
    Q_GADGET
};

Q_DECLARE_METATYPE(project_ptr);

然后在我的主类(一个QWindow)中,我有一个函数来发射信号,实际的信号,以及一个用来处理消息的槽函数:
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);
    ...
};

如我们所见,类可以包含任何你想要的东西(几乎),但类型是通过复制来使用的(没有引用,没有指针)。
为了触发事件,我会调用project_changed()函数,该函数会创建一个带有项目指针的project_ptr,并使用Qt的emit ...功能发送它。
void snap_builder::project_changed(project::pointer_t p)
{
    project_ptr ptr;
    ptr.f_ptr = p;
    emit projectChanged(ptr);
}

最后,你必须像这样连接那个事件,在我的构造函数中完成:
connect(this, &snap_builder::projectChanged,
        this, &snap_builder::on_project_changed);

我觉得有点复杂,但是结果还是符合预期的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接