使用自定义类型发出信号不起作用

Dmi*_*nov 8 qt

我正在尝试使用自定义类型发出信号.Type使用Q_DECLARE_METATYPE声明,并使用qRegisterMetaType注册.

当我发出信号时,我得到输出流的下一个错误:

Type "MyType" has id:  1024 ; register status:  true
QObject::connect: Cannot queue arguments of type 'MyType' (Make sure 'MyType' is registered using qRegisterMetaType().)
Run Code Online (Sandbox Code Playgroud)

只有在使用排队连接时(当对象位于不同的线程或使用显式时Qt::QueuedConnection)并且 MyType在命名空间内声明时,Bug才是可重现的.

示例代码:MyType.h

#define SHOW_BUG

#ifdef SHOW_BUG

    namespace NS
    {
        struct MyType
        {
            int val;
        };
    }
    Q_DECLARE_METATYPE( NS::MyType );

#else

    struct MyType
    {
        int val;
    };
    Q_DECLARE_METATYPE( MyType );

#endif
Run Code Online (Sandbox Code Playgroud)

MyClass.h:

#include "MyType.h"

namespace NS
{

    class MyClass
        : public QObject
    {
        Q_OBJECT
    public:
        MyClass( QObject *parent = NULL );
        ~MyClass();

    signals:
        void sendMyType( const MyType& tt );

    public slots:
        void invokeBug();
        void getMyType( const MyType& tt );
    };

}
Run Code Online (Sandbox Code Playgroud)

MyClass.cpp

#include <QDebug>

namespace NS
{

    MyClass::MyClass(QObject *parent)
        : QObject(parent)
    {
        qRegisterMetaType< MyType >();
    }

    MyClass::~MyClass()
    {
    }

    void MyClass::invokeBug()
    {
        const int id = qMetaTypeId< MyType >();
        const bool test = QMetaType::isRegistered( id );
        qDebug() << "Type \"MyType\" has id: " << id << "; register status: " << test;

        MyType tt;
        tt.val = 42;
        emit sendMyType( tt );
    }

    void MyClass::getMyType( MyType const& tt )
    {
        qDebug() << "Slot fired: " << tt.val;
    }

}
Run Code Online (Sandbox Code Playgroud)

Main.cpp的

#include "MyClass.h"

int main(int argc, char *argv[])
{
    QCoreApplication a( argc, argv );

    NS::MyClass c1;
    NS::MyClass c2;
    QThread thread;
    thread.start();

    c2.moveToThread( &thread );

    QObject::connect( &c1, &NS::MyClass::sendMyType, &c2, &NS::MyClass::getMyType );
    QTimer::singleShot( 0, &c1, SLOT( invokeBug() ) );

    return a.exec();
}
Run Code Online (Sandbox Code Playgroud)

Dmi*_*nov 13

得到了Qt团队的回答.非常奇怪的用例,但是:必须使用完整命名空间声明信号.这是对moc的限制,因为它没有完整的C++解析器.

所以,这将工作:

  class MyObject {
    ...
    // correct
    Q_SIGNAL void sendMyType( const NS::MyType& tt );
  };
Run Code Online (Sandbox Code Playgroud)

但这不会:

namespace NS {
  ...
  class MyObject {
    ...
    // wrong
    Q_SIGNAL void sendMyType( const MyType& tt );
  };
}
Run Code Online (Sandbox Code Playgroud)


Rei*_*ica 9

下面的代码说明了失败和解决方案.它适用于Qt 4和Qt 5.

Now we fail 
QObject::connect: No such signal NS::Object::badSignal(NS::MyType) in ../metatype-21119397/main.cpp:32
Now we succeed 
Successful slot call 1 
Run Code Online (Sandbox Code Playgroud)
#include <QCoreApplication>
#include <QDebug>

namespace NS {
    struct MyType
    {
        int val;
        MyType() {}
        MyType(int v) : val(v) {}
    };

    class Object : public QObject {
        Q_OBJECT
    public:
        Q_SIGNAL void goodSignal(const NS::MyType &);
        Q_SIGNAL void badSignal(const MyType &);
        Q_SLOT void slot(const NS::MyType & x) {
            qDebug() << "Successful slot call" << x.val;
        }
    };
}
Q_DECLARE_METATYPE(NS::MyType)

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    NS::Object src, dst;
    qRegisterMetaType<NS::MyType>();

    qDebug() << "Now we fail";
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
    QObject::connect(&src, &NS::Object::badSignal, &dst, &NS::Object::slot, Qt::QueuedConnection);
#else
    dst.connect(&src, SIGNAL(badSignal(NS::MyType)), SLOT(slot(NS::MyType)), Qt::QueuedConnection);
#endif
    emit src.goodSignal(NS::MyType(1));

    qDebug() << "Now we succeed";
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
    QObject::connect(&src, &NS::Object::goodSignal, &dst, &NS::Object::slot, Qt::QueuedConnection);
#else
    dst.connect(&src, SIGNAL(goodSignal(NS::MyType)), SLOT(slot(NS::MyType)), Qt::QueuedConnection);
#endif
    emit src.goodSignal(NS::MyType(1));

    return a.exec();
}

#include "main.moc"
Run Code Online (Sandbox Code Playgroud)