標準 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[]
、シグナルに渡された引数へのポインターで満たされたベクトルです。ここでは特に何もありません。
引数 vector が に渡され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[]
前のベクトルを関数呼び出しに解決するもう一方の端が含まれています。また、可変引数リスト (省略記号を使用...
) やその他の疑わしいトリックが含まれていないこともわかります。
したがって、元の質問を啓発するために、たとえばが信号の署名に一致する にsomeSignal(double)
接続されている場合、呼び出しは に解決され、期待どおりに引数を渡すだけです。secondSlot(double)
case 1
qt_static_metacall
firstSlot()
シグナルより引数の少ないにシグナルを接続すると、呼び出しは に解決されcase 0
、firstSlot()
引数なしで呼び出されます。void *_a[]
シグナルに渡された引数は、そのベクトルにそのまま残ります。