2014-01-14 13 views
6

私はカスタムタイプで信号を放射しようとしています。型はQ_DECLARE_METATYPEで宣言され、qRegisterMetaTypeで登録されています。カスタムタイプの信号を送信できません

Iが信号を発するとき、Iは、出力ストリームに次のエラーを得る:(オブジェクトが異なるスレッドであるか、または明示的な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チームからの回答を得た作品。非常に奇妙な用途ですが、シグナルフルネームスペースと宣言する必要があります。これは完全なC++パーサを持たないので、mocの制限です。

ので、これは動作します:

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がネームスペースにあることを知ることができません。なぜなら、MyTypeが完全なC++パーサを必要とするからです。 –

+0

私はReSharperのルールを作成します:) –

+1

これはおそらくmoc-ngで修正できますが、これは本質的に「本格的なC++パーサー」であるclangパーサーを使用しているためです。 ;-) – lpapp

関連する問題