it-swarm-pt.tech

Tipo de retorno '?:' (Operador condicional ternário)

Por que o primeiro retorna uma referência?

int x = 1;
int y = 2;
(x > y ? x : y) = 100;

Enquanto o segundo não?

int x = 1;
long y = 2;
(x > y ? x : y) = 100;

Na verdade, o segundo não foi compilado - "não foi o valor restante da tarefa".

207
Yola

As expressões não têm tipos de retorno, elas têm um tipo e - como é conhecido no padrão C++ mais recente - uma categoria de valor.

Uma expressão condicional pode ser um lvalue ou um rvalue . Esta é a sua categoria de valor. (Isso é uma simplificação, em C++11 temos lvalues, xvalues ​​e prvalues.)

Em termos muito amplos e simples, um lvalue refere-se a um objeto na memória e um rvalue é apenas um valor que pode não estar necessariamente associado a um objeto na memória.

Uma expressão de atribuição atribui um valor a um objeto, portanto a coisa a ser atribuída deve ser um lvalue .

Para que uma expressão condicional (?:) seja um lvalue (novamente, em termos amplos e simples), o segundo e o os terceiros operandos devem ser lvalues ​​ do mesmo tipo. Isso ocorre porque o tipo e a categoria de valor de uma expressão condicional são determinados no tempo de compilação e devem ser apropriados, independentemente de a condição ser verdadeira ou não. Se um dos operandos precisar ser convertido em um tipo diferente para corresponder ao outro, a expressão condicional não poderá ser um valor lvalue , pois o resultado dessa conversão não seria ser um lvalue .

Referências ISO/IEC 14882: 2011:

3.10 [basic.lval] Valores e valores (sobre categorias de valor)

5.15 [expr.cond] Operador condicional (regras para que tipo e categoria de valor uma expressão condicional possui)

5.17 [expr.ass] Operadores de atribuição e atribuição composta (requisito de que o l.h.s. de uma atribuição deva ser um valor modificável)

173
CB Bailey

O tipo da expressão ternária ?: é o tipo comum de seu segundo e terceiro argumento. Se os dois tipos forem iguais, você receberá uma referência novamente. Se eles podem ser convertidos um no outro, um é escolhido e o outro é convertido (promovido neste caso). Como você não pode retornar uma referência lvalue para uma temporária (a variável convertida/promovida), seu tipo é um tipo de valor.

57
Xeo

Ele não pode retornar um lvalue , pois terá que promover implicitamente o tipo de x para corresponder ao tipo de y (já que ambos os lados de : não são do mesmo tipo) e com isso precisam criar um temporário.


O que diz o padrão? ( n1905 )

Expressões 5.17 Operadores de atribuição e atribuição composta

5.17/3

Se o segundo e o terceiro operando tiverem tipos diferentes e tiverem um tipo de classe (possivelmente qualificado para cv), será feita uma tentativa de converter cada um desses operandos no tipo do outro. O processo para determinar se uma expressão de operando E1 do tipo T1 pode ser convertida para corresponder a uma expressão de operando E2 do tipo T2 é definida da seguinte maneira:

- Se E2 for um valor l: E1 pode ser convertido para corresponder a E2 se E1 puder ser implicitamente convertido (cláusula 4) no tipo "referência a T2", sujeito à restrição de que na conversão a referência deve se vincular diretamente (8.5.3 ) para E1.

- Se E2 for um rvalor ou se a conversão acima não puder ser feita:

- se E1 e E2 tiverem tipo de classe e os tipos de classe subjacentes forem os mesmos ou um for uma classe base da outra: E1 poderá ser convertido para corresponder a E2 se a classe de T2 for do mesmo tipo ou uma classe base de , a classe de T1 e a qualificação cv de T2 são a mesma qualificação cv que ou uma qualificação cv maior que a qualificação cv de T1. Se a conversão for aplicada, E1 será alterado para um rvalor do tipo T2 que ainda se refere ao objeto de classe de origem original (ou seu subobjeto apropriado). [ Nota: ou seja, nenhuma cópia é feita. - nota final ] copiando-inicializando um temporário do tipo T2 de E1 e usando esse temporário como operando convertido.

Caso contrário (por exemplo, se E1 ou E2 tiver um tipo não de classe, ou se ambos tiverem tipos de classe, mas as classes subjacentes não forem iguais ou uma classe base da outra): E1 pode ser convertido para corresponder E2 se E1 puder ser implicitamente convertido no tipo que a expressão E2 teria se E2 fosse convertido em um rvalor (ou o tipo que possui, se E2 for um rvalor).

Utilizando esse processo, é determinado se o segundo operando pode ser convertido para corresponder ao terceiro operando e se o terceiro operando pode ser convertido para corresponder ao segundo operando. Se ambos puderem ser convertidos ou um puder ser convertido, mas a conversão for ambígua, o programa será mal formado. Se nenhum dos dois puder ser convertido, os operandos permanecerão inalterados e uma verificação adicional será realizada conforme descrito abaixo. Se exatamente uma conversão for possível, essa conversão será aplicada ao operando escolhido e o operando convertido será usado no lugar do operando original pelo restante desta seção.


5.17/4

Se o segundo e o terceiro operandos são lvalues ​​e têm o mesmo tipo, o resultado é desse tipo e é um lvalue e é um campo de bits se o segundo ou o terceiro operando for um campo de bits ou se ambos forem de bit. Campos.


5.17/5

Caso contrário, o resultado é um rvalue. Se o segundo e o terceiro operandos não tiverem o mesmo tipo e tiverem um tipo de classe (possivelmente qualificado para CV), a resolução de sobrecarga será usada para determinar as conversões (se houver) a serem aplicadas aos operandos (13.3.1.2, 13.6) . Se a resolução da sobrecarga falhar, o programa está mal formado. Caso contrário, as conversões assim determinadas são aplicadas e os operandos convertidos são usados ​​no lugar dos operandos originais pelo restante desta seção.

19
Filip Roséen - refp