¿Los paréntesis alrededor del resultado son significativos en una declaración de devolución?


79

¿Existe alguna diferencia entre estas dos declaraciones dentro de una función?

bool returnValue = true;
// Code that does something
return(returnValue);

¿y esto?

bool returnValue = true;
// Code
return returnValue;

El primero tiene paréntesis returnValue.


Gracias Rob, capturaste con éxito el espíritu de la pregunta. En esencia, me preguntaba si el compilador hizo algo especial (como intentar evaluar la expresión primero) o si simplemente la ignoró.
Jose Villalta

1
Es difícil responder a esta pregunta para cualquier c++ / c. Sería bueno ser más específico en la definición del lenguaje, pero no sé cómo solucionarlo 9 años después.
Jonas Stein

Respuestas:


122

A partir de C ++ 14, a menudo lo son.

C ++ 14 agrega un caso marginal donde los paréntesis alrededor de un valor de retorno pueden alterar la semántica. Este fragmento de código muestra la declaración de dos funciones. La única diferencia son los paréntesis alrededor del valor de retorno.

int var1 = 42;
decltype(auto) func1() { return var1; } // return type is int, same as decltype(var1)
decltype(auto) func1() { return(var1); } // return type is int&, same as decltype((var1))

En el primero func1devuelve un inty en el segundo func1devuelve un int&. La diferencia semántica está directamente relacionada con los paréntesis que la rodean .

El autoespecificador en su forma más reciente se introdujo en C ++ 11. En la especificación del lenguaje C ++ se describe como:

Especifica que el tipo de variable que se declara se deducirá automáticamente de su inicializador. Para funciones, especifica que el tipo de retorno es un tipo de retorno final o se deducirá de sus declaraciones de retorno (desde C ++ 14)

Además, C ++ 11 introdujo el decltypeespecificador que se describe en las especificaciones del lenguaje C ++ :

Inspecciona el tipo declarado de una entidad o consulta el tipo de retorno de una expresión.

[recorte]

  1. Si el argumento es el nombre sin paréntesis de un objeto / función, o es una expresión de acceso de miembro (object.member o pointer-> member), entonces decltype especifica el tipo declarado de la entidad especificada por esta expresión.

  2. Si el argumento es cualquier otra expresión de tipo T, entonces

    a) si la categoría de valor de la expresión es xvalue, entonces decltype especifica T &&

    b) si la categoría de valor de expresión es lvalue, entonces decltype especifica T &

    c) de lo contrario, decltype especifica T

[recorte]

Tenga en cuenta que si el nombre de un objeto está entre paréntesis, se convierte en una expresión lvalue, por lo que decltype (arg) y decltype ((arg)) suelen ser tipos diferentes.

En C ++ 14, decltype(auto)se permitía la capacidad de uso para los tipos de devolución de funciones. Los ejemplos originales son donde entra en juego la diferencia semántica entre paréntesis. Revisando los ejemplos originales:

int var1 = 42;
decltype(auto) func1() { return var1; } // return type is int, same as decltype(var1)
decltype(auto) func1() { return(var1); } // return type is int&, same as decltype((var1))

decltype(auto)permite que el tipo de retorno final en la función se deduzca de la entidad / expresión en la declaración de retorno. En la primera versión return var1;es efectivamente lo mismo que devolver el tipo decltype(var1)(un inttipo de devolución según la regla 1 anterior) y en el segundo caso return (var1);es efectivamente lo mismo que decltype((var1))(un int &tipo de devolución según la regla 2b).

Los paréntesis hacen el tipo de retorno en int&lugar de int, por lo tanto, un cambio en la semántica. Moraleja de la historia: "No todos los paréntesis de un tipo de devolución son iguales"


La declaración de retorno sin paréntesis sigue siendo una expresión lvalue, ¿verdad? A menos que se trate como un valor x en ese escenario. ¿Puede explicar la categoría de valor de la devolución sin paréntesis?
void.pointer

1
La instrucción return devuelve una lectura de la expresión introducida en ella, es decir, captura un valor r de la expresión que contiene y lo devuelve. Nunca devolvemos un valor l. Es posible que algún compilador tenga un error que coincida con la descripción que da aquí, y por las razones que da aquí, pero nunca debería ser el caso que return (x);sea ​​equivalente a return &x;, ni debería ser posible que resulte en una devolución de el valor de x pero con el tipo de referencia ax.
Theodore Murdock

4
Vaya, qué espantoso lenguaje. Totalmente ... opaco. Buen comentario, gracias.
Paul Sanders

5
C ++ es un lenguaje extremadamente interesante. Pero este tipo de "características" ocultas me
vuelven

Nuestro código está lleno de esos paréntesis innecesarios. También usamos con autobastante frecuencia. ¿Nuestra semántica nunca cambia mientras nos mantengamos alejados decltype? Temo un comportamiento inesperado cuando pasamos a la siguiente versión del compilador que incorpora el próximo Visual Studio.
OneWorld

6

No hay diferencia.

Una razón para usar paréntesis sería si quisiera evaluar una expresión antes de regresar, pero en su ejemplo, no habría ninguna razón. Ver:

Paréntesis que rodean los valores devueltos

para mayor discusión.


3
Aunque incluso con una expresión complicada, estos paréntesis todavía no causan un comportamiento diferente. Simplemente hacen que el significado sea más obvio (¡subjetivamente!) Para los lectores humanos.
aschepler

@Karl "Una razón para usar paréntesis sería si quisiera evaluar una expresión antes de regresar" ¿Puede dar un ejemplo de esto?
Chris Middleton

3
@ChrisMiddleton No, porque la afirmación es tan absurda aquí como lo fue en ese hilo. No hay diferencia alguna entre funcional return m * x + cy return (m * x + c)o return ( (m * x) + c )o etc - y que no se ve mejor o más intuitivo o bien, si me preguntas.
underscore_d

5

Los paréntesis del ejemplo superior son superfluos; son efectivamente ignorados.

Sería lo mismo que algo como ...

int x = (5);

Los paréntesis aquí también se ignoran.


Bueno, técnicamente, no se ignoran , simplemente no tienen ningún efecto sobre el valor de la expresión.
John Bode

1
@John: efectivamente ignorado. :)
James

3
+1 ... esta es la única respuesta que establece que los paréntesis son en realidad redundantes y muestra que su uso es un poco estúpido.
Konrad Rudolph

4

AFAIK, nada es diferente.

En C ++, las expresiones pueden tener la forma: expro (expr). Entonces, esta última es una expresión con más escritura. Para leer más sobre esto, consulte una gramática (busque "expresión").


David, gracias por el enlace. Tengo la gramática en el libro de C ++ de Stroustrup, pero (por pereza, supongo) no la miro mucho, ahora que la tengo marcada en mi navegador, puedo consultarla con más frecuencia.
Jose Villalta


3

Supongo que booes un error tipográfico y se pregunta si hay una diferencia entre

return expr;

y

return(expr);

La respuesta es no.


2

¡¡Ninguna diferencia!!

La gente usa paréntesis si hay una expresión compleja involucrada.

Por cierto, returnes una declaración, no una función.


2

No, no hay diferencia entre los dos, aunque puede incluir paréntesis si hace que la expresión sea fácil de leer y clara.


1
... pero nunca lo hace. ¿Por qué lo haría? ¿Qué es difícil de leer sobre una expresión sin paréntesis? Agregar paréntesis me parece un desorden. En cuanto a parecer más claro, ¿la gente piensa que returnes un operador codicioso y que return m * x + cpodría regresar my descartar el resto, o qué?
undercore_d

1

¡Estás ralentizando abusivamente el compilador!

La presencia de paréntesis no solo ralentiza la fase de preprocesamiento, sino que también genera un árbol de sintaxis abstracta más complicado: más memoria, más cálculo.


¿Desde un punto de vista semántico? Son exactamente idénticos. Ya sea que haya paréntesis o no, la returndeclaración evaluará completamente la expresión antes de devolverla.


5
Mi pensamiento exactamente. Al hacer que el compilador haga un trabajo innecesario para analizar el desorden inútil, se está acercando a la muerte térmica del universo sin una buena razón.
Maxim Egorushkin

4
¿Qué opinas de los bitcoins?
Jeremy Nikolai

0

Son idénticos. Veo la sintaxis entre paréntesis con bastante frecuencia y siempre les pregunto a quienes la usan: ¿por qué ? Y nadie puede responder por qué lo usan.

Para resumir sin rodeos, las personas que no comprenden bien la diferencia entre macros y funciones similares a funciones, o que están confundidas acerca de la precedencia de los operadores o el orden de las reglas de evaluación en C. estilo se beneficia del uso de paréntesis.

Así

return value;

es más correcto que

return (value)

porque este último sugiere que no sabes muy bien lo que estás haciendo :)


-3

Ambos son iguales en tu caso.


MM, ¿podría explicar su comentario?
Zeshan Khan

1
si aes 5entonces return a++;y return (a++);(que es lo mismo) ambos regresarán5
MM

2
específicamente, postinc / decrement devuelve el valor de pre-modificación de su operando, y ninguna cantidad de paréntesis u otros intentos infructuosos de coerción cambiarán eso.
subrayado_d
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.