O assunto foi discutido antes , mas isso não é uma duplicata.
Quando alguém pergunta sobre a diferença entre decltype(a)
e decltype((a))
, a resposta usual é - a
é uma variável, (a)
é uma expressão. Acho esta resposta insatisfatória.
Primeiro, a
é uma expressão também. As opções para uma expressão primária incluem, entre outras -
- (expressão)
- expressão id
Mais importante, o fraseado para decltype considera parênteses muito, muito explicitamente :
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, ...
Então a questão permanece. Por que os parênteses são tratados de maneira diferente? Alguém está familiarizado com documentos técnicos ou discussões de comitês por trás disso? A consideração explícita entre parênteses leva a pensar que isso não é um descuido, então deve haver uma razão técnica que me falta.
c++
c++11
language-lawyer
decltype
Ofek Shilon
fonte
fonte
(a)
é uma expressão ea
é uma expressão e uma variável".Respostas:
Não é uma supervisão. É interessante que em Decltype e auto (revisão 4) (N1705 = 04-0145) exista uma declaração:
Mas no Decltype (revisão 6): redação proposta (N2115 = 06-018), uma das mudanças é
Não há justificativa na redação, mas suponho que essa seja uma extensão do tipo de declty usando uma sintaxe um pouco diferente; em outras palavras, ele pretendia diferenciar esses casos.
O uso para isso é mostrado no C ++ draft9.2.8.4:
O que é realmente interessante, é como ele funciona com a
return
declaração:Meu Visual Studio 2019 sugere que eu remova parênteses redundantes, mas na verdade eles se transformam em
decltype((i))
quais alterações retornam valor para oint&
que o torna UB desde que retornaram referência a uma variável local.fonte
Parênteses não são tratados de maneira diferente. É a expressão de identificação não parênteses que é tratada de maneira diferente.
Quando os parênteses estão presentes, as regras regulares para todas as expressões se aplicam. O tipo e a categoria de valor são extraídos e codificados no tipo de
decltype
.A provisão especial existe para que possamos escrever código útil com mais facilidade. Ao aplicar
decltype
ao nome de uma variável (membro), geralmente não queremos um tipo que represente as propriedades da variável quando tratada como uma expressão. Em vez disso, queremos apenas o tipo com o qual a variável é declarada, sem ter que aplicar uma tonelada de características de tipo para chegar a ela. E é exatamente isso quedecltype
é especificado para nos dar.Se nos importamos com as propriedades da variável como uma expressão, ainda podemos obtê-la com bastante facilidade, com um par extra de parênteses.
fonte
int
membroi
dea
,decltype(a.i)
éint
enquantodecltype((a.i))
éint&
(assumindo quea
não éconst
)? Desde que a expressãoa.i
é atribuível?a.i
é um valor não-const-lvalue, portanto, você obtém um tipo de referência não-const lvalue para(a.i)
.&
, xvalues são&&
e prvalues não são tipos de referência.Antes do C ++ 11, a linguagem precisa de ferramentas para obter dois tipos diferentes de informações :
Devido à natureza dessas informações, os recursos tiveram que ser adicionados no idioma (isso não pode ser feito em uma biblioteca). Isso significa novas palavras-chave. O padrão poderia ter introduzido duas novas palavras-chave para isso. Por exemplo,
exprtype
para obter o tipo de uma expressão edecltype
obter o tipo de declaração de uma variável. Essa teria sido a opção clara e feliz.No entanto, o comitê padrão sempre se esforçou ao máximo para evitar a introdução de novas palavras - chave no idioma para minimizar a quebra do código antigo. A compatibilidade com versões anteriores é uma filosofia central do idioma.
Assim, com C ++ 11 nós temos apenas uma palavra-chave usada por duas coisas diferentes:
decltype
. A maneira como diferencia os dois usos é tratando de maneiradecltype(id-expression)
diferente. Foi uma decisão consciente do comitê, um (pequeno) compromisso.fonte
export
foi introduzido. Se você pode terexport
(anteriormente todos os modelos eram "exportados" por padrão)), você pode ter coisas comodecltype
econstexpr
. Obviamente, adicionarregister
em outro idioma seria problemático.