Usar emitir vs llamar a una señal como si fuera una función regular en Qt

97

Digamos que tengo esta señal:

signals:
    void progressNotification(int progress);

Recientemente aprendí sobre la palabra clave emit en Qt. Hasta ahora, solía ejecutar señales llamándolas como una función regular. Entonces en lugar de:

emit progressNotification(1000 * seconds);

Yo escribiría:

progressNotification(1000 * seconds);

Llamarlos así parecía funcionar, y todas las ranuras conectadas se ejecutarían, entonces, ¿usar la palabra clave emit causa un comportamiento diferente, o es solo azúcar sintáctico?

sashoalm
fuente
17
+1 Nunca supe emitno es necesario. Sin embargo, es extraño que haya aprendido emitmucho después de llamar a las señales directamente, ya que el sistema de ranura de señal es una de las primeras cosas que debe aprender sobre Qt.
Christian Rau

Respuestas:

88

emites simplemente azúcar sintáctico. Si observa la salida preprocesada de la función que emite una señal, verá emitque acaba de desaparecer.

La "magia" ocurre en el código generado para la función de emisión de señales, que puede observar inspeccionando el código C ++ generado por moc.

Por ejemplo, una fooseñal sin parámetros genera esta función miembro:

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

Y el código emit foo();está preprocesado para simplementefoo();

emitse define en Qt/qobjectdefs.h(en el sabor de código abierto de la fuente de todos modos), así:

#ifndef QT_NO_EMIT
# define emit
#endif

(La protección de definición es para permitirle usar Qt con otros marcos que tienen nombres en no_keywordsconflicto a través de la opción de configuración QMake).

Estera
fuente
14
¿Sabe si alguna vez hubo una implementación (o una implementación planificada) de un emitque realmente hizo más que nada? Encuentro que tener el 'azúcar sintáctico' en este caso solo confunde al novato (o al menos a mí cuando era un usuario novato de Qt) - parece que algo mágico o importante está sucediendo con la emitpseudo-palabra clave, cuando no hace nada en todo: toda la magia ocurre en una función antigua regular que moccrea ( moces la magia para las señales Qt y las ranuras). emitEs una decoración innecesaria que no hace más que parecer importante.
Michael Burr
12
Emit no es "solo decoración". emitle dice a la persona que lee la llamada que la magia está a punto de suceder (es decir, esto activará el código en objetos de los que esta clase posiblemente nunca haya oído hablar, y estas llamadas pueden ser sincrónicas o asincrónicas), lo que esencialmente se pierde por completo si omite la palabra clave. Úselo. Se documenta automáticamente. Los "principiantes" deben leer documentos y tutoriales, y emitsiempre está ahí (de todos modos, en los documentos oficiales). Descubrir que puede simplemente llamar a la función debería suceder después de haber "visto la luz"; ya no es un novato en ese momento.
Mat
19
Mmm, no estoy seguro de estar de acuerdo contigo en lo valiosa que es la emit'palabra clave'. Creo que hubiera preferido que se usara una convención de nomenclatura si fuera necesario dejar en claro que una llamada a función es una señal.
Michael Burr
2
Bueno, estoy radicalmente en desacuerdo con eso :) Forzar una convención de nomenclatura es algo que puede hacer usted mismo en sus proyectos / lugar de trabajo, Qt no evita eso. Qt no te obliga a usar la "palabra clave", e incluso te permite desactivarla si choca con otras partes de tu código. En mi opinión, el enfoque de palabras clave es mejor: el compilador no puede ayudarlo a hacer cumplir las políticas de nomenclatura, pero detectará un error ortográfico emit.
Mat
15
Para ser claros, no estaba defendiendo que se usara una convención de nomenclatura, solo que si el motivo de un emitcomentario de palabra clave pseudo era dejar en claro que se está invocando una señal, entonces una convención de nomenclatura podría hacer lo mismo, sin misterio y con beneficios similares. Qt no pudo hacer cumplir la convención de nomenclatura (en realidad, mocpodría hacerla cumplir, pero tampoco estoy defendiendo eso), pero Qt no puede hacer cumplir el uso de emitninguno de los dos. Y aunque puede 'apagar' emitsi hay un conflicto de nombres, eso no ayuda mucho si tiene un montón de archivos fuente que lo están usando (innecesariamente, para arrancar).
Michael Burr
2

Después de 18 meses ... comencé con comentarios en la respuesta de @ Mat, y me estaba quedando sin espacio rápidamente. De ahí la respuesta.

IMO emitno es azúcar sintáctico ni una palabra clave simple en el sentido de que

  1. Genera código (como explica @Mat arriba),
  2. Ayuda al connectmecanismo a reconocer que de hecho es un signal, y
  3. Hace que su señal sea parte de un sistema "más grande", donde las señales y respuestas (ranuras) se pueden ejecutar de forma sincrónica o asincrónica, o en cola, dependiendo de dónde y cómo se emitió la señal. Esta es una característica extremadamente útil del sistema de señal / ranura.

Todo el sistema de señal / ranura es un idioma diferente al de una simple llamada de función. Creo que se deriva del patrón del observador. También hay una gran diferencia entre ay signala slot: no es necesario implementar una señal , ¡mientras que una ranura debe serlo !

Estás caminando por la calle y ves una casa en llamas (una señal). Usted marca el 911 ( conecte la señal de incendio con la ranura de respuesta del 911 ). La señal solo fue emitida , mientras que la ranura fue implementada por el departamento de bomberos. Puede ser impreciso, pero entiendes la idea. Veamos el ejemplo de OP.

Algún objeto de backend sabe cuánto se ha avanzado. Entonces podría simplemente emit progressNotification(...)señalar. Depende de la clase que muestra la barra de progreso real, recoger esta señal y ejecutarla. Pero, ¿cómo se conecta la vista a esta señal? Bienvenido al sistema de señal / ranura de Qt. Ahora se puede concebir una clase de administrador (normalmente una especie de widget), que consta de un objeto de vista y un objeto de cálculo de datos (ambos son QObjects), que puede realizar connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress).

No entremos en los aspectos de diseño de la clase de administrador, pero basta con decir que aquí es donde brilla el sistema de señal / ranura. Puedo concentrarme en diseñar una arquitectura muy limpia para mi aplicación. No siempre, pero muchas veces, encuentro que simplemente emito señales pero implemento ranuras .

Si es posible usar / llamar a un método de señal sin siquiera emitirlo , entonces necesariamente implica que nunca necesitó esa función como señal en primer lugar.

NombreRakes
fuente
6
No, de emithecho es solo una macro vacía y puramente opcional. No así las palabras clave signaly slotque son procesadas por el moc. signalse usa para proporcionar la implementación de la función, slotse usa para crear la entrada del meta objeto para que se encuentre con la SLOT(MySlot())macro o en QML. emites suggar sintáctico. Nada se quejará nunca si escribe emit i++;(pero tal vez sus compañeros de trabajo) y aún no puede conectarse i++.
derM
-5

La segunda opción implicaría que siempre sabrá cuál es el nombre de la función y los parámetros de la función y que el objeto al que lo está enviando es conocido por esa función en particular. Esos dos casos no siempre son ciertos, por lo que son las dos cosas principales por las que se han creado ranuras y señales. "debajo del capó", el mecanismo de señal y ranura es solo una tabla con indicadores para cada función que está conectada.

Además, mire este pdf que explica muy claramente la naturaleza de las señales y el mecanismo de ranuras: http://www.elpauer.org/stuff/a_deeper_look_at_signals_and_slots.pdf

Evert
fuente
Ambas formas requieren conocer el nombre de la señal y sus parámetros: la estás emitiendo, ¿cómo podrías emitir algo que no conoces? Ambos tienen la misma semántica también, son idénticos.
Mat
1
¿Quizás estás arruinando una llamada de señal con una llamada de ranura directa? Pero debo admitir que también me pregunté sobre el título de la pregunta al principio, ya que nunca supe que emitera solo una operación no válida. Pero incluso en este caso, la lectura del cuerpo de la pregunta debería haber aclarado las cosas, así que -1.
Christian Rau