2013-08-22 9 views
6

は、それが有効なのparamsなしQtでより少ないパラメータでスロットに信号を接続できますか?

QObject::connect(a, SIGNAL(somesig(someparam)), b, SLOT(someslot())); 

を呼び出すことですか?それは動作する(ランタイム例外がスローされない)ようだが、私はドキュメント内の参照を見つけることができません。私が見つけたのは、someslotにデフォルトのパラメータがある場合に可能です。この場合有効です。しかし、私のメソッドsomeslotは、デフォルト(この例ではパラメータなし)と同じパラメータを設定していません。

したがって、パラメータを少なくしてスロットに信号を配線することは可能ですか?

答えて

9

はい、問題ありません。 Signals & Slotsドキュメントには、短い文章があります。

[...]信号の署名は、受信スロットの署名と一致する必要があります。 (実際にはスロットは、それは追加の引数を無視することができますので、それは受信信号よりも短い署名を有することができる。)[...]

そのような例は、さらに、デフォルトの引数はページの下にもあります説明した。

+0

これはC++標準にも準拠していますか、それともQtごとに動作することが保証されている機能ですか?少なくともC言語では、ISO/IEC 9899:TC2 §6.5.2.2p6でUBにつながります。 – Kamajii

+0

@Kamajii:スロット呼び出しは直接関数呼び出しではありません。 UBは存在しません。Qtは関数を正しく呼び出します。 – Mat

+0

もちろん、通常の呼び出し(+キュー接続など)だけのスロット呼び出しです。シグナルが最後に自動生成(moc) 'qt_static_metacall'メンバーに到達すると、非常に問題が発生します。 – Kamajii

1

標準のC++では、Qtソリューションも同様に機能します。

信号がメソッドを呼び出すことによって行われている発光:

emit someSignal(3.14); 

emitキーワードは、実際には空#defineに解決するので、上記の行は、ただ与えられた引数を持つメソッドsomeSignalを呼び出します。この方法は、そのようQObject由来のクラス内で宣言されている可能性があります

class SomeObject: public QObject { 
    Q_OBJECT 
public slots: 
    void firstSlot() { /* implementation */ } 
    void secondSlot(double) { /* implementation */ } 

signals: 
    void someSignal(double); /* no implementation here */ 
}; 

これはあなたに馴染みのように見えるはずです、まだあなたの信号の実際の実装はどこから来たあなたは疑問に思っているかもしれません。お察しのとおりQtのメタオブジェクトコンパイラ(MOC)がで蹴るところ、これは、その生成されたソースおおよそ次のようになります実装に提供signalsセクション内を宣言すべてのメソッドのために:。

void SomeObject::someSignal(double _t1) 
{ 
    void *_a[] = { Q_NULLPTR, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) }; 
    QMetaObject::activate(this, &staticMetaObject, 1, _a); 
} 

興味深い部分はvoid *_a[]ベクトルで、シグナルに渡される引数へのポインタで埋められています。特にここには何もありません。

引数ベクトルはQMetaObject::activateに渡され、スレッドセーフチェックやその他のハウスキーピングが行われ、信号に接続されているスロットがあれば呼び出しを開始します。ランタイムに信号対スロット接続が解決されるため(connect()の動作と同様に)、MOCからの少しの助けが再び必要となります。特に、MOCもqt_static_metacall()実装クラスを生成します。

void SomeObject::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) 
{ 
    if (_c == QMetaObject::InvokeMetaMethod) { 
     SomeObject *_t = static_cast<SomeObject *>(_o); 
     Q_UNUSED(_t) 
     switch (_id) { 
     case 0: _t->firstSlot(); break; 
     case 1: _t->secondSlot((*reinterpret_cast< double(*)>(_a[1]))); break; 
     default: ; 
     } 
    } /* some more magic */ 
} 

あなたが見ることができるように、この方法は、関数呼び出しに前からvoid *_a[]ベクトルを解決するためのもう一方の端が含まれています。また、variadic引数リスト(省略記号、...を使用)や他の不審なトリッキーがないことがわかります。

元の質問を啓発するには:someSignal(double)が信号のシグネチャと一致するsecondSlot(double)に接続されている場合、コールはqt_static_metacallcase 1に解決され、予想通りに引数が渡されます。

シグナルよりも引数の数が少ないfirstSlot()にシグナルを接続すると、コールはcase 0に解決され、引数なしでfirstSlot()が呼び出されます。信号に渡された引数は、そのままvoid *_a[]ベクトルにそのまま残ります。

関連する問題