¿Cuál es el nombre de esta funcionalidad de C ++?

82

Estaba escribiendo código C ++ y omití por error el nombre de una función WSASocket. Sin embargo, mi compilador no generó un error y asoció my SOCKETcon el valor entero 1 en lugar de un socket válido.

El código en cuestión debería haberse visto así:

this->listener = WSASocket(address->ai_family, address->ai_socktype, address->ai_protocol, NULL, NULL, WSA_FLAG_OVERLAPPED);

Pero en cambio, se veía así:

this->listener = (address->ai_family, address->ai_socktype, address->ai_protocol, NULL, NULL, WSA_FLAG_OVERLAPPED);

Viniendo de otros idiomas, parece que puede ser algún tipo de tipo anónimo. ¿Cuál es el nombre de la función, en caso de que sea realmente una función?

¿Cual es su propósito?

Es difícil buscarlo cuando no sabes por dónde empezar.

Michael J. Gray
fuente
3
+1, buena pregunta para un concurso de pub (o una pregunta espantosa de entrevista para empresas a las que les gusta contratar personas que sean buenas en acertijos).
Betsabé
8
Enlace al artículo de Wikipedia sobre el operador de coma . FWIW, uno de los usos comunes es obtener dos efectos secundarios en una forexpresión de iteración de bucle * , ala para (int i = 0, j = 0; i <10; ++ i, --j) ... `
Tony Delroy
1
@ MichaelJ.Gray Técnicamente estás equivocado. No sobrescribe el comportamiento. Imagine: xyj i=0;j=0;x=i++,j=6;serían 6 y yo sería de todos modos 1. Si el comportamiento de i ++ se sobrescribiera, permanecería 0. Pero cada declaración se invoca y después de alcanzar ,solo todas las extensiones se descartan y se invoca el siguiente pseudopunto de secuencia. Entonces, el primero =simplemente asigna la parte después del último, ,pero se invoca cada punto. De todos modos: no entiendo por qué su compilador no le advierte sobre la redefinición de la declaración de función y, en cambio, cambia su código a algo de comportamiento diferente
dhein
5
Si usa un compilador adecuado, con las advertencias activadas, le advertirá sobre este tipo de código dudoso, por ejemplo gccy g++con la -Wallopción diga:warning: left-hand operand of comma expression has no effect [-Wunused-value]
Sam Watkins
3
Entonces, en mi opinión, la mejor respuesta a esta pregunta es "habilitar siempre las advertencias"; luego, el propio compilador explicará que hay un error y le dirá lo que hizo; y esta respuesta también te solucionará muchos otros problemas.
Sam Watkins

Respuestas:

151

El operador de coma † evalúa el lado izquierdo, descarta su valor y, como resultado, produce el lado derecho. WSA_FLAG_OVERLAPPEDes 1, y ese es el resultado de la expresión; todos los demás valores se descartan. Nunca se crea ningún socket.


† A menos que esté sobrecargado. Sí, se puede sobrecargar. No, no debes sobrecargarlo. ¡Aléjate del teclado, ahora mismo!

R. Martinho Fernandes
fuente
9
+1, boost spirit sobrecarga de manera muy efectiva el operador de coma, pero esa es una excepción muy solitaria a la regla: no lo hagas .
Betsabé
2
@Bathsheba Boost.Assign también sobrecarga el operador de coma, pero ¿quién lo usa desde C ++ 11?
rubenvb
39
Pero tuviste la mejor explicación de lo terrible que puede ser la poderosa coma. Implacable y lleno de burlas, atormentó mi código durante varios minutos mientras me miraba sin vergüenza por su comportamiento.
Michael J. Gray
3
Relacionado: ¿ Cuándo sobrecargar el operador de coma?
moooeeeep
1
@ R.MartinhoFernandes - Eigen también sobrecarga muy eficazmente el operador de coma. Consulte esta pregunta de SE para ver algunos ejemplos de uso.
David Hammen
22

El operador de coma le da sentido a su código.

De hecho, está configurando lo this->listener = WSA_FLAG_OVERLAPPED;que resulta ser sintéticamente válido.

Betsabé
fuente
3
No solo es válido sintácticamente, sino que dado que la API de Windows no es segura para los tipos, también es una conversión válida.
MSalters
5
@MSalters no es que POSIX sea mucho mejor en ese sentido
chbaker0
1
Es por eso que los constructores invocables con un solo argumento deberían ser explícitos , entonces se habría producido un error del compilador y el desarrollador habría tenido la oportunidad de echar un segundo vistazo a esta extraña construcción.
Matthieu M.
@MSalters Bueno, SOCKETes un typedef para unsigned inty WSA_FLAG_OVERLAPPEDes un intliteral. Si SOCKETfuera un sinónimo de int, ni siquiera sería una conversión .
Joker_vD
1
@Joker_vD: De hecho. Si lo hubieran hecho un typedef struct __socket*, tendríamos menos errores. Pero hay demasiado código por ahí que "sabe" que SOCKETes integral.
MSalters
21

El compilador está evaluando cada punto de secuencia a su vez dentro del paréntesis y el resultado es la expresión final, WSA_FLAG_OVERLAPPEDen la expresión.

El operador de coma ,es un punto de secuencia en C ++. La expresión a la izquierda de la coma se evalúa por completo antes que la expresión a la derecha. El resultado es siempre el valor de la derecha. Cuando tienes una expresión de la forma (x1, x2, x3, ..., xn) el resultado de la expresión es siempre xn.

Sean
fuente
Una vez que haya agregado su aclaración allí, tiene más sentido. Al principio, no entendía muy bien la relevancia del problema del punto de secuencia.
Michael J. Gray