Utiliser emit vs appeler un signal comme s'il s'agissait d'une fonction régulière dans Qt

97

Disons que j'ai ce signal:

signals:
    void progressNotification(int progress);

Je n'ai appris que récemment sur le mot-clé emit dans Qt. Jusqu'à présent, j'exécutais des signaux en les appelant simplement comme une fonction normale. Donc au lieu de:

emit progressNotification(1000 * seconds);

Je souhaiterai écrire:

progressNotification(1000 * seconds);

Les appeler comme ça semblait fonctionner, et tous les slots connectés s'exécuteraient, l'utilisation du mot-clé emit provoquait-elle un comportement différent, ou est-ce juste du sucre syntaxique?

sashoalm
la source
17
+1 Jamais su emitn'est pas nécessaire. C'est étrange cependant que vous ayez appris emitlongtemps après avoir appelé directement les signaux, car le système de créneaux de signaux est l'une des premières choses à apprendre sur Qt.
Christian Rau

Réponses:

88

emitest juste du sucre syntaxique. Si vous regardez la sortie pré-traitée de la fonction qui émet un signal, vous verrez qu'elle emitest juste partie.

La "magie" se produit dans le code généré pour la fonction d'émission de signal, que vous pouvez regarder en inspectant le code C ++ généré par moc.

Par exemple, un foosignal sans paramètre génère cette fonction membre:

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

Et le code emit foo();est pré-traité pour simplementfoo();

emitest défini dans Qt/qobjectdefs.h(dans la version open-source de la source de toute façon), comme ceci:

#ifndef QT_NO_EMIT
# define emit
#endif

(La garde de définition est de vous permettre d'utiliser Qt avec d'autres frameworks qui ont des noms en collision via l' no_keywordsoption de configuration QMake.)

Tapis
la source
14
Savez-vous s'il y a déjà eu une implémentation (ou une implémentation planifiée) d'un emitqui a fait plus que rien? Je trouve que le fait d'avoir le 'sucre syntaxique' dans ce cas ne fait que confondre le novice (ou du moins moi quand j'étais un utilisateur novice de Qt) - il semble que quelque chose de magique ou d'important se passe avec le emitpseudo-mot-clé, quand il ne fait rien à all - toute la magie se produit dans une ancienne fonction régulière qui moccrée ( mocc'est la magie pour les signaux et les slots Qt). emitest une décoration inutile qui ne fait que paraître importante.
Michael Burr
12
Emit n'est pas "que de la décoration". emitindique à la personne qui lit l'appel que la magie est sur le point de se produire (c'est-à-dire que cela va déclencher du code dans des objets dont cette classe n'a potentiellement jamais entendu parler, et que ces appels peuvent être synchrones ou asynchrones), ce qui est essentiellement totalement perdu si vous omettez le mot-clé. Utilise le. C'est une documentation automatique. Les "novices" devraient lire les documents et les tutoriels, et emitsont toujours là (dans les documents officiels de toute façon). Découvrir que vous pouvez simplement appeler la fonction devrait se produire après avoir "vu la lumière" - vous n'êtes plus un novice à ce stade.
Mat
19
Hmm, je ne suis pas sûr d'être d'accord avec vous sur la valeur du emit"mot-clé". Je pense que j'aurais préféré qu'une convention de dénomination soit utilisée s'il était nécessaire de préciser qu'un appel de fonction est un signal.
Michael Burr
2
Eh bien, je ne suis pas du tout d'accord avec ça :) Forcer une convention de nommage est quelque chose que vous pouvez faire vous-même dans vos projets / lieu de travail, Qt ne l'empêche pas. Qt ne vous oblige pas à utiliser le "mot-clé", et vous permet même de le désactiver s'il entre en conflit avec d'autres parties de votre code. À mon avis, l'approche par mot-clé est meilleure - le compilateur ne peut pas vous aider à appliquer les politiques de dénomination, mais il détectera une faute d'orthographe emit.
Mat
15
Pour être clair - je ne préconisais pas l'utilisation d'une convention de dénomination - juste que si la raison d'un emitpsuedo-keyword-comment était de préciser qu'un signal est appelé, alors une convention de dénomination pourrait faire de même, sans mystère et avec des avantages similaires. La convention de dénomination ne peut pas être appliquée par Qt (en fait, mocpourrait l'appliquer - mais je ne le préconise pas non plus), mais Qt ne peut pas imposer l'utilisation de l'un emitou l'autre. Et bien que vous puissiez `` désactiver '' emits'il y a un conflit de nom, cela n'aide pas beaucoup si vous avez un tas de fichiers source qui l'utilisent (inutilement, pour démarrer).
Michael Burr
2

Après 18 mois ... j'ai commencé par des commentaires sous la réponse de @ Mat, et je manquais rapidement de place. Ainsi la réponse.

IMO emitn'est ni un sucre syntaxique ni un simple mot-clé dans le sens où

  1. Il génère du code (comme expliqué par @Mat ci-dessus),
  2. Cela aide le connectmécanisme à reconnaître qu'il s'agit effectivement d'un signal, et
  3. Cela fait de votre signal une partie d'un système "plus grand", où les signaux et les réponses (slots) peuvent être exécutés de manière synchrone ou asynchrone, ou mis en file d'attente, selon l'endroit et la manière dont le signal a été émis. C'est une fonction extrêmement utile du système signal / slot.

L'ensemble du système signal / slot est un idiome différent d'un simple appel de fonction. Je crois que cela découle du modèle d'observateur. Il y a aussi une différence majeure entre a signalet a slot: un signal n'a pas à être implémenté, alors qu'un slot doit l'être !

Vous marchez dans la rue et voyez une maison en feu (un signal). Vous composez le 911 ( connectez le signal d'incendie à l'emplacement de réponse 911 ). Le signal n'a été émis que tandis que le créneau a été mis en œuvre par les pompiers. Peut-être imprécis, mais vous voyez l'idée. Regardons l'exemple de OP.

Certains objets backend savent combien de progrès ont été réalisés. Donc, cela pourrait simplement emit progressNotification(...)signaler. C'est à la classe qui affiche la barre de progression réelle, de capter ce signal et de l'exécuter. Mais comment la vue se connecte-t-elle à ce signal? Bienvenue dans le système signal / slot de Qt. On peut maintenant concevoir une classe de gestionnaire (typiquement un widget de sortes), qui se compose d'un objet de vue et d'un objet de calcul de données (les deux étant QObjects), peut fonctionner connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress).

N'entrons pas dans les aspects de conception de la classe de gestionnaire, mais il suffit de dire que c'est là que le système signal / slot brille. Je peux me concentrer sur la conception d'une architecture très propre pour mon application. Pas toujours, mais souvent, je trouve que j'émets simplement des signaux mais que j'implémente des slots .

S'il est possible d'utiliser / d'appeler une méthode de signal sans jamais l'émettre , cela implique nécessairement que vous n'avez jamais eu besoin de cette fonction comme signal en premier lieu.

NomRâteaux
la source
6
Non, ce emitn'est en effet qu'une macro vide et purement facultative. Ce n'est pas le cas des mots-clés signalet slotqui sont traités par le moc. signalest utilisé pour fournir l'implémentation de la fonction, slotest utilisé pour créer l'entrée de méta-objet afin qu'il soit trouvé avec la SLOT(MySlot())macro ou dans QML. emitest un suggestion syntaxique. Rien ne se plaindra jamais si vous écrivez emit i++;(mais peut-être vos collègues) et que vous ne pouvez toujours pas vous connecter i++.
derM
-5

La seconde option impliquerait que vous sachiez toujours quel est le nom de la fonction et les paramètres de la fonction et que l'objet auquel vous l'envoyez est connu par cette fonction particulière. Ces deux cas ne sont pas toujours vrais, ce sont donc les deux principales raisons pour lesquelles des créneaux et des signaux ont été créés. "sous le capot", le mécanisme de signal et de fente n'est qu'un tableau avec des pointeurs vers chaque fonction connectée.

Regardez également ce pdf qui explique très clairement la nature du mécanisme des signaux et des slots: http://www.elpauer.org/stuff/a_deeper_look_at_signals_and_slots.pdf

Evert
la source
Les deux méthodes nécessitent de connaître le nom du signal et ses paramètres - vous l'émettez, comment pourriez-vous émettre quelque chose que vous ne connaissez pas? Les deux ont la même sémantique, ils sont identiques.
Mat
1
Peut-être que vous gâchez un appel de signal avec un appel de slot direct? Mais je dois admettre que je me suis aussi interrogé sur le titre de la question au début, car je ne savais pas que emitc'était juste un no-op. Mais même dans ce cas, la lecture du corps de la question aurait dû éclaircir les choses, donc -1.
Christian Rau