Le sujet a été discuté auparavant , mais ce n'est pas un doublon.
Lorsque quelqu'un demande la différence entre decltype(a)
et decltype((a))
, la réponse habituelle est - a
est une variable, (a)
est une expression. Je trouve cette réponse insatisfaisante.
Tout d'abord, a
c'est aussi une expression. Les options pour une expression primaire incluent, entre autres -
- ( expression )
- id-expression
Plus important encore, le phrasé pour decltype considère les parenthèses très, très explicitement :
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, ...
La question demeure donc. Pourquoi les parenthèses sont - elles traitées différemment? Quelqu'un connaît-il les documents techniques ou les discussions en comité qui se cachent derrière? La considération explicite des parenthèses conduit à penser que ce n'est pas un oubli, donc il doit y avoir une raison technique qui me manque.
la source
(a)
est une expression, eta
est une expression et une variable".Réponses:
Ce n'est pas un oubli. Il est intéressant de noter que dans Decltype et auto (révision 4) (N1705 = 04-0145), il y a une déclaration:
Mais dans Decltype (révision 6): libellé proposé (N2115 = 06-018) l' un des changements est
Il n'y a aucune justification dans le libellé, mais je suppose que c'est une sorte d'extension du decltype en utilisant une syntaxe un peu différente, en d'autres termes, il était destiné à différencier ces cas.
L'utilisation pour cela est montrée dans C ++ draft9.2.8.4:
Ce qui est vraiment intéressant, c'est comment cela fonctionne avec la
return
déclaration:Mon Visual Studio 2019 me suggère de supprimer les parenthèses redondantes, mais en fait, elles se transforment en
decltype((i))
changements qui retournent la valeur àint&
ce qui en fait UB depuis le retour de la référence à une variable locale.la source
Les parenthèses ne sont pas traitées différemment. C'est l'expression id sans parenthèse qui est traitée différemment.
Lorsque les parenthèses sont présentes, les règles normales pour toutes les expressions s'appliquent. Le type et la catégorie de valeur sont extraits et codifiés dans le type de
decltype
.La disposition spéciale est là pour que nous puissions écrire plus facilement du code utile. Lors de l'application
decltype
au nom d'une variable (membre), nous ne voulons généralement pas d'un type qui représente les propriétés de la variable lorsqu'elle est traitée comme une expression. Au lieu de cela, nous voulons juste le type avec lequel la variable est déclarée, sans avoir à appliquer une tonne de traits de type pour y accéder. Et c'est exactement ce quidecltype
est spécifié pour nous donner.Si nous nous soucions des propriétés de la variable en tant qu'expression, nous pouvons toujours l'obtenir assez facilement, avec une paire de parenthèses supplémentaire.
la source
int
membrei
dea
,decltype(a.i)
estint
toutdecltype((a.i))
estint&
(en supposant quea
nonconst
)? Puisque l'expressiona.i
est assignable?a.i
est une valeur l non constante, vous obtenez donc un type de référence valeur non constante pour(a.i)
.&
, les valeurs x le sont&&
et les valeurs pr ne sont pas des types de référence.Avant C ++ 11, le langage a besoin d'outils pour obtenir deux types d'informations différents :
En raison de la nature de ces informations, les fonctionnalités ont dû être ajoutées dans la langue (cela ne peut pas être fait dans une bibliothèque). Cela signifie de nouveaux mots-clés. La norme aurait pu introduire deux nouveaux mots clés pour cela. Par exemple
exprtype
pour obtenir le type d'une expression etdecltype
pour obtenir le type de déclaration d'une variable. Cela aurait été l'option claire et heureuse.Cependant, le comité standard a toujours fait de son mieux pour éviter d'introduire de nouveaux mots clés dans la langue afin de minimiser la rupture de l'ancien code. La rétrocompatibilité est une philosophie fondamentale du langage.
Donc , avec C ++ 11 nous avons eu un seul mot - clé utilisé pour deux choses différentes:
decltype
. La façon dont il différencie les deux utilisations consiste à traiterdecltype(id-expression)
différemment. C'était une décision consciente du comité, un (petit) compromis.la source
export
été introduit. Si vous pouvez avoirexport
(auparavant tous les modèles étaient par défaut "exportés"), vous pouvez avoir des trucs commedecltype
etconstexpr
. De toute évidence, l'ajoutregister
dans une autre langue serait problématique.