2013-08-22 3 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를 호출 신호를 방사하는

는 메소드를 호출하여 수행됩니다.

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

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

이 익숙 보인다해야 아직 신호의 실제 구현이 어디에서 오는지 당신이 궁금해 수 있습니다 방법은 지금처럼 QObject 유도 된 클래스 내에서 선언되었을 수 있습니다. . 당신이 추측 할 수 있듯이, 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[] 벡터를 해결하기 위해 다른 쪽 끝을 포함한다. 또한 가변 인수 목록 (줄임표 사용, ...) 또는 다른 의심스러운 속임수가없는 것을 볼 수 있습니다.

그래서 원래 질문을 계몽하는 것이 좋습니다.someSignal(double)이 신호의 서명과 일치하는 secondSlot(double)에 연결되면 qt_static_metacall에있는 case 1으로 전화가 연결되고 예상대로 인수가 전달됩니다.

신호보다 더 적은 인수를 가진 firstSlot()에 신호를 연결할 때, 호출은 case 0으로 해결되고 인수없이 firstSlot()이 호출됩니다. 신호에 전달 된 인수는 void *_a[] 벡터에서 그대로 유지됩니다.