C++ 14 añade una franja caso donde los paréntesis alrededor de un valor de retorno pueden alterar la semántica. Este fragmento de código muestra dos funciones que se declaran. La única diferencia es 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 los primeros func1
devuelve un int
y en el segundo func1
devuelve un int&
. La diferencia en semántica está directamente relacionada con el paréntesis circundante.
El especificador auto
en su última forma se introdujo en C++ 11. En el C++ Language Spec se describe como:
especifica que el tipo de la variable que se está declarada será automáticamente deduce de su inicializador. Para las funciones, especifica que el tipo de retorno es un trailing tipo retorno o se deduce de sus estados de retorno (desde C++ 14)
Como bien C++ 11 introducido el especificador decltype
que se describe en el C++ Language Spec:
Inspecciona el tipo de declaración de una entidad o pregunta el tipo de devolución de una expresión.
[snip]
Si el argumento es el nombre unparenthesised de un objeto/función, o es una expresión del acceso de miembros (object.member Puntero-> miembro o), entonces el decltype especifica el tipo declarado de la entidad especificada por esta expresión.
Si el argumento es cualquier otra expresión de tipo T, entonces
a) si la categoría valor de la expresión es xValue, entonces el decltype especifica T & &
b) si la categoría valor de expresión se lvalue, entonces el decltype especifica T &
c) en caso contrario, decltype especifica T
[snip]
Tenga en cuenta que si el nombre de un objeto se parenthesised, se convierte en una expresión valor-I, por lo tanto decltype (arg) y decltype ((arg)) a menudo son diferentes tipos.
En C++ 14 la capacidad de utilizar decltype(auto)
se dejó para este tipo de retorno de la función. Los ejemplos originales son donde entra en juego la diferencia semántica con 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 el tipo de retorno final en la función que se deduce de la entidad/expresión en la instrucción de retorno. En la primera versión return var1;
es efectivamente lo mismo que devolver el tipo decltype(var1)
(un int
tipo de devolución según la regla 1 anterior) y en el segundo caso return (var1);
es efectivamente el mismo que decltype((var1))
(un tipo de devolución int &
según la regla 2b).
Los paréntesis hacen el tipo de retorno int&
en lugar de int
, por lo tanto, un cambio en la semántica. Moraleja de la historia: "No todos los paréntesis en un tipo de devolución se crean iguales"
Prepárese para algunas insignias. Curiosamente, estas preguntas * siempre * obtienen la mayor cantidad de visitas. –
Bienvenido a Stack Overflow, Jose. Por favor, tome nota de la edición que hice a su pregunta. Menciona específicamente el cambio entre los dos bloques de código, lo que ahorra a los lectores la frustración de tener que jugar [detectar la diferencia] (http://www.spotthedifference.com/) con su código. También ayuda a las personas a reconocer cuándo una diferencia fue intencional en lugar de un simple error tipográfico (como 'boo'). –
Gracias Rob, has capturado con éxito el espíritu de la pregunta. En Essence me preguntaba si el compilador hizo algo especial (como tratar de evaluar la expresión primero) o si simplemente lo ignoró. –