El tema se discutió antes , pero esto no es un duplicado.
Cuando alguien pregunta sobre la diferencia entre decltype(a)
y decltype((a))
, la respuesta habitual es: a
es una variable, (a)
es una expresión. Encuentro esta respuesta insatisfactoria.
Primero, a
es una expresión también. Las opciones para una expresión primaria incluyen, entre otras:
- ( expresión )
- expresión-id
Más importante aún, la redacción de decltype considera los paréntesis de manera muy, muy explícita :
For an expression e, the type denoted by decltype(e) is defined as follows:
(1.1) if e is an unparenthesized id-expression naming a structured binding, ...
(1.2) otherwise, if e is an unparenthesized id-expression naming a non-type template-parameter, ...
(1.3) otherwise, if e is an unparenthesized id-expression or an unparenthesized class member access, ...
(1.4) otherwise, ...
Entonces la pregunta permanece. ¿Por qué los paréntesis son tratados de manera diferente? ¿Alguien está familiarizado con los documentos técnicos o las discusiones del comité detrás de esto? La consideración explícita de paréntesis lleva a pensar que esto no es un descuido, por lo que debe haber una razón técnica que me falta.
fuente
(a)
es una expresión ya
es una expresión y una variable".Respuestas:
No es un descuido. Es interesante que en Decltype y auto (revisión 4) (N1705 = 04-0145) hay una declaración:
Pero en Decltype (revisión 6): redacción propuesta (N2115 = 06-018) uno de los cambios es
No hay una justificación en la redacción, pero supongo que esto es una especie de extensión de decltype usando una sintaxis un poco diferente, en otras palabras, tenía la intención de diferenciar estos casos.
El uso para eso se muestra en C ++ draft9.2.8.4:
Lo que es realmente interesante es cómo funciona con la
return
declaración:Mi Visual Studio 2019 me sugiere que elimine los paréntesis redundantes, pero en realidad se convierten en
decltype((i))
cambios que devuelven el valor queint&
lo convierte en UB desde que devuelve la referencia a una variable local.fuente
Los paréntesis no se tratan de manera diferente. Es la expresión id sin paréntesis la que se trata de manera diferente.
Cuando los paréntesis están presentes, se aplican las reglas regulares para todas las expresiones. El tipo y la categoría de valor se extraen y codifican en el tipo de
decltype
.La disposición especial está ahí para que podamos escribir código útil más fácilmente. Cuando se aplica
decltype
al nombre de una variable (miembro), generalmente no queremos algún tipo que represente las propiedades de la variable cuando se trata como una expresión. En cambio, solo queremos el tipo con el que se declara la variable, sin tener que aplicar una tonelada de rasgos de tipo para llegar a ella. Y eso es exactamente lo quedecltype
se especifica para darnos.Si nos preocupamos por las propiedades de la variable como expresión, aún podemos obtenerla con bastante facilidad, con un par adicional de paréntesis.
fuente
int
miembroi
dea
,decltype(a.i)
esint
whiledecltype((a.i))
isint&
(suponiendoa
que noconst
)? Dado que la expresióna.i
es asignable?a.i
es un valor de valor no constante, por lo que se obtiene un tipo de referencia de valor no constante(a.i)
.&
, los valores x son&&
, y los valores no son tipos de referencia.Pre C ++ 11, el lenguaje necesita herramientas para obtener dos tipos diferentes de información :
Debido a la naturaleza de esta información, las características tuvieron que agregarse en el idioma (no se puede hacer en una biblioteca). Eso significa nuevas palabras clave. El estándar podría haber introducido dos nuevas palabras clave para esto. Por ejemplo,
exprtype
para obtener el tipo de una expresión ydecltype
para obtener el tipo de declaración de una variable. Esa habría sido la opción clara y feliz.Sin embargo, el comité estándar siempre ha hecho todo lo posible por evitar la introducción de nuevas palabras clave en el idioma para minimizar la ruptura del código antiguo. La compatibilidad con versiones anteriores es una filosofía central del lenguaje.
Así que con C ++ 11 llegamos sólo una palabra clave utilizada por dos cosas diferentes:
decltype
. La forma en que diferencia entre los dos usos es tratando de maneradecltype(id-expression)
diferente. Fue una decisión consciente del comité, un compromiso (pequeño).fuente
export
se introdujo. Si puede tenerexport
(anteriormente todas las plantillas se "exportaron" por defecto), puede tener cosas comodecltype
yconstexpr
. Obviamente agregarregister
en otro idioma sería problemático.