2014-01-14 27 views
6

我试图用自定义类型发射信号。类型声明为Q_DECLARE_METATYPE并注册为qRegisterMetaType用自定义类型发射信号不起作用

当我发出的信号,然后我得到下一个错误输出流:仅当排队连接被使用(当对象是在不同的线程或用来明确Qt::QueuedConnection

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

错误是可再现MyType在名称空间内声明。

样品的编号: 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 

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); 
    }; 

} 

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; 
    } 

} 

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(); 
} 

回答

8

下面的代码说明了失败和解决方案。它适用于双方的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 
#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" 
9

得到了Qt的团队答案。非常奇怪的用例,但:信号必须声明为全名空间。这是moc的限制,来自它没有一个完整的C++解析器。

所以,这将工作:

class MyObject { 
    ... 
    // correct 
    Q_SIGNAL void sendMyType(const NS::MyType& tt); 
    }; 

但这不会:

namespace NS { 
    ... 
    class MyObject { 
    ... 
    // wrong 
    Q_SIGNAL void sendMyType(const MyType& tt); 
    }; 
} 
+0

你会注意到它,如果你已经看过我的代码:)记住:MOC是愚蠢的。它不知道MyType是否在命名空间中,因为它需要一个完整的C++解析器。 –

+0

我将为ReSharper创建一个规则:) –

+1

这可能可以用moc-ng修复,不过因为这是使用clang解析器,它本质上是一个“完整的C++解析器”。 ;-) – lpapp