Używanie emit vs wywoływanie sygnału tak, jakby to była zwykła funkcja w Qt

97

Powiedzmy, że mam ten sygnał:

signals:
    void progressNotification(int progress);

Dopiero niedawno dowiedziałem się o słowie kluczowym emit w Qt. Do tej pory wykonywałem sygnały, po prostu wywołując je jak zwykłą funkcję. Więc zamiast:

emit progressNotification(1000 * seconds);

Napisałbym:

progressNotification(1000 * seconds);

Nazywanie ich w ten sposób wydawało się działać, a wszystkie połączone sloty zostałyby wykonane, więc czy użycie słowa kluczowego emit powoduje inne zachowanie, czy jest to po prostu cukier składniowy?

sashoalm
źródło
17
+1 Nie wiedziałem, emitnie jest potrzebne. To jednak dziwne, że nauczyłeś się o tym emitdługo po bezpośrednim wywołaniu sygnałów, ponieważ system slotów sygnałowych jest jedną z pierwszych rzeczy, których można się nauczyć o Qt.
Christian Rau

Odpowiedzi:

88

emitto tylko cukier syntaktyczny. Jeśli spojrzysz na wstępnie przetworzone wyjście funkcji, która emituje sygnał, zobaczysz, że po emitprostu go nie ma.

„Magia” dzieje się w wygenerowanym kodzie funkcji emitującej sygnał, na którą można spojrzeć, sprawdzając kod C ++ wygenerowany przez moc.

Na przykład foosygnał bez parametrów generuje tę funkcję składową:

void W::foo()
{
    QMetaObject::activate(this, &staticMetaObject, 0, 0);
}

A kod emit foo();jest wstępnie przetwarzany w prosty sposóbfoo();

emitjest zdefiniowany w Qt/qobjectdefs.h(w każdym razie w wersji źródłowej typu open source), na przykład:

#ifndef QT_NO_EMIT
# define emit
#endif

(Definicja ochrony polega na umożliwieniu używania Qt z innymi frameworkami, które mają kolidujące nazwy za pośrednictwem no_keywordsopcji konfiguracyjnej QMake.)

Mata
źródło
14
Czy wiesz, czy kiedykolwiek wdrożono (lub zaplanowano wdrożenie) emitczegoś, co faktycznie dało więcej niż nic? Uważam, że posiadanie `` cukru syntaktycznego '' w tym przypadku po prostu dezorientuje nowicjusza (lub przynajmniej mnie, gdy byłem początkującym użytkownikiem Qt) - wydaje się, że coś magicznego lub ważnego dzieje się z emitpseudo-słowem kluczowym, kiedy nic nie robi all - cała magia dzieje się w zwykłej starej funkcji, która moctworzy ( mocjest magią dla sygnałów i gniazd Qt). emitto niepotrzebna dekoracja, która nic nie robi, ale wydaje się ważna.
Michael Burr
12
Emitowanie to nie „tylko dekoracja”. emitinformuje osobę czytającą wywołanie, że magia ma się wydarzyć (tj. spowoduje to uruchomienie kodu w obiektach tej klasy, o których potencjalnie nigdy nie słyszano, a wywołania te mogą być synchroniczne lub asynchroniczne), co jest całkowicie utracone, jeśli pominiesz słowo kluczowe. Użyj tego. To jest automatyczne dokumentowanie. „Nowicjusze” powinni czytać dokumentację i tutoriale, i emitjest tam zawsze (w każdym razie w oficjalnych dokumentach). Odkrycie, że możesz po prostu wywołać tę funkcję, powinno nastąpić po „zobaczeniu światła” - w tym momencie nie jesteś już nowicjuszem.
Mat
19
Hmm, nie jestem pewien, czy zgadzam się z Tobą co do wartości emitsłowa kluczowego. Myślę, że wolałbym zastosować konwencję nazewnictwa, jeśli istnieje potrzeba wyjaśnienia, że ​​wywołanie funkcji jest sygnałem.
Michael Burr
2
Cóż, radykalnie się z tym nie zgadzam :) Wymuszanie konwencji nazewnictwa to coś, co możesz zrobić sam w swoich projektach / miejscu pracy, Qt temu nie zapobiega. Qt nie zmusza cię do używania „słowa kluczowego”, a nawet pozwala ci go wyłączyć, jeśli koliduje z innymi częściami twojego kodu. Moim zdaniem podejście do słów kluczowych jest lepsze - kompilator nie może pomóc w egzekwowaniu zasad nazewnictwa, ale wykryje błąd pisowni emit.
Mat
15
Żeby było jasne - nie opowiadałem się za stosowaniem konwencji nazewnictwa - tylko, że jeśli powodem emitpseudo-słowa kluczowego było wyjaśnienie, że wywoływany jest sygnał, to konwencja nazewnictwa mogłaby zrobić to samo, bez tajemnica i podobne korzyści. Konwencja nazewnictwa nie może być egzekwowana przez Qt (w rzeczywistości mocmogłaby ją wymusić - ale ja też tego nie popieram), ale Qt nie może wymusić użycia emitżadnego z nich. I chociaż możesz `` wyłączyć '', emitjeśli występuje konflikt nazw, nie pomaga to zbytnio, jeśli masz kilka plików źródłowych, które go używają (niepotrzebnie, aby uruchomić).
Michael Burr
2

Po 18 miesiącach ... zacząłem od komentarzy pod odpowiedzią @ Mata i szybko kończyło się miejsce. Tak więc odpowiedź.

IMO emitnie jest ani cukrem syntaktycznym, ani prostym słowem kluczowym w tym sensie

  1. Generuje kod (jak wyjaśniono powyżej @Mat),
  2. Pomaga connectmechanizmowi rozpoznać, że rzeczywiście jest to element signala
  3. Dzięki temu sygnał staje się częścią „większego” systemu, w którym sygnały i odpowiedzi (szczeliny) mogą być wykonywane synchronicznie lub asynchronicznie lub w kolejce, w zależności od tego, gdzie i jak został wyemitowany. Jest to niezwykle przydatna cecha systemu sygnał / szczelina.

Cały system sygnału / szczelin to inny idiom niż proste wywołanie funkcji. Uważam, że wynika to ze wzoru obserwatora. Istnieje również zasadnicza różnica między a signali a slot: sygnał nie musi być implementowany, podczas gdy gniazdo musi być !

Idziesz ulicą i widzisz płonący dom (sygnał). Wybierasz numer 911 ( podłącz sygnał pożaru do gniazda odpowiedzi 911 ). Sygnał był tylko emitowany , natomiast szczelina została zrealizowana przez straż pożarną. Może być nieprecyzyjne, ale masz pomysł. Spójrzmy na przykład OP.

Jakiś obiekt zaplecza wie, jaki postęp został osiągnięty. Więc może po prostu emit progressNotification(...)sygnalizować. Do klasy, która wyświetla rzeczywisty pasek postępu, należy odebranie tego sygnału i wykonanie na nim. Ale w jaki sposób widok łączy się z tym sygnałem? Witamy w systemie sygnałów / gniazd Qt. Można teraz wyobrazić sobie klasę menedżera (zwykle pewnego rodzaju widget), która składa się z obiektu widoku i obiektu obliczeniowego danych (oba są QObjects), które może wykonać connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress).

Nie wchodźmy w aspekty projektowe klasy menedżera, ale wystarczy powiedzieć, że tutaj świeci system sygnału / gniazda. Mogę skupić się na zaprojektowaniu bardzo czystej architektury dla mojej aplikacji. Nie zawsze, ale często okazuje się, że po prostu emituję sygnały, ale wdrażam sloty .

Jeśli możliwe jest użycie / wywołanie metody sygnału bez jej emitowania , oznacza to , że w pierwszej kolejności nigdy nie potrzebowałeś tej funkcji jako sygnału .

NameRakes
źródło
6
Nie, emitjest rzeczywiście tylko pustym makrem i czysto opcjonalnym. Nie tak to słowa kluczowe signal, a slotktóre są przetwarzane przez MOC. signalsłuży do realizacji funkcji, slotsłuży do tworzenia wpisu obiektu meta, tak aby można go było znaleźć za pomocą SLOT(MySlot())makra lub w QML. emitjest suggarem syntaktycznym. Nic nigdy nie będzie narzekać, jeśli napiszesz emit i++;(ale może twoi współpracownicy), a nadal nie możesz się połączyć i++.
derM
-5

Druga opcja oznaczałaby, że zawsze wiesz, jaka jest nazwa funkcji i jej parametry oraz że obiekt, do którego ją wysyłasz, jest znany tej konkretnej funkcji. Te dwa przypadki nie zawsze są prawdziwe, więc to są dwie główne przyczyny, dla których stworzono szczeliny i sygnały. „pod maską” mechanizm sygnalizacyjno-szczelinowy to po prostu tabela ze wskazówkami do każdej podłączonej funkcji.

Spójrz także na ten plik PDF, który bardzo jasno wyjaśnia naturę mechanizmu sygnałów i szczelin: http://www.elpauer.org/stuff/a_deeper_look_at_signals_and_slots.pdf

Wynicować
źródło
Obie drogi wymagają znajomości nazwy sygnału i jego parametrów - emitujesz go, jak możesz emitować coś, czego nie znasz? Obie mają tę samą semantykę, są identyczne.
Mat
1
Może psujesz połączenie sygnałowe z bezpośrednim wywołaniem szczeliny? Ale muszę przyznać, że początkowo zastanawiałem się również nad tytułem pytania, ponieważ nigdy nie wiedziałem, że emitto tylko nie-op. Ale nawet w tym przypadku czytanie treści pytania powinno było wyjaśnić, więc -1.
Christian Rau