Tipo de retorno de '?:' (Operador condicional ternario)


208

¿Por qué el primero devuelve una referencia?

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

Mientras que el segundo no?

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

En realidad, el segundo no compiló en absoluto: "no queda el valor restante de la asignación".


1
hmm, eso es como encontrar un caso especial para la cocción de pan, ni de una vez llegaron a esta
Ulterior


Como asignar un tipo a la expresión implicaría un reparto de al menos un término, este término ya no sería un valor l.
Yves Daoust

Respuestas:


173

Las expresiones no tienen tipos de retorno, tienen un tipo y, como se conoce en el último estándar de C ++, una categoría de valor.

Una expresión condicional puede ser un lvalue o un rvalue . Esta es su categoría de valor. (Esto es algo así como una simplificación, C++11ya que tenemos lvalues, xvalues ​​y prvalues).

En términos muy amplios y simples, un valor l se refiere a un objeto en la memoria y un valor r es solo un valor que no necesariamente se puede adjuntar a un objeto en la memoria.

Una expresión de asignación asigna un valor a un objeto, por lo que la cosa a la que debe asignarse debe ser un valor l .

Para que una expresión condicional ( ?:) sea un valor l (nuevamente, en términos amplios y simples), el segundo y tercer operandos deben ser valores del mismo tipo . Esto se debe a que la categoría de tipo y valor de una expresión condicional se determina en tiempo de compilación y debe ser apropiada independientemente de si la condición es verdadera o no. Si uno de los operandos debe convertirse a un tipo diferente para que coincida con el otro, entonces la expresión condicional no puede ser un valor l, ya que el resultado de esta conversión no sería un valor l .

ISO / IEC 14882: 2011 referencias:

3.10 [basic.lval] Lvalues ​​and rvalues ​​(sobre categorías de valores)

5.15 [expr.cond] Operador condicional (reglas para qué tipo y categoría de valor tiene una expresión condicional)

5.17 [expr.ass] Asignación y operadores de asignaciones compuestas (requisito de que las lhs de una asignación deben ser un valor l modificable)


3
Y cuando leí sobre xvalue y prvalue (ya que no había oído hablar de ellos antes de su respuesta) me encontré con esta útil publicación SO: stackoverflow.com/questions/3601602/…
mullido

an rvalue is just a value that may not necessarily be *attached* to an object in memory.¿Puedes explicar esto en un término más simple? . Además, ¿qué quieres decir con type and value *category*? Gracias
Mr.Anubis

@SoulReaper: prvalue, xvalue, glvalueson categorías de valores.
Xeo

@Xeo Agradezco la ayuda, pero ¿puedes decir qué quiere decir con un valor r es solo un valor que no necesariamente se puede adjuntar a un objeto en la memoria. ? con ejemplo?
Mr.Anubis

@SoulReaper: Creo que está hablando de cosas como true, this, enumvalores. Esas cosas son valores (valores "puros"), pero no viven en la memoria.
Xeo

57

El tipo de la ?:expresión ternaria es el tipo común de su segundo y tercer argumento. Si ambos tipos son iguales, obtendrá una referencia de nuevo. Si son convertibles entre sí, uno se elige y el otro se convierte (promovido en este caso). Como no puede devolver una referencia lvalue a una temporal (la variable convertida / promovida), su tipo es un tipo de valor.


pero y mayor que x, por lo que no es necesario en la promoción para este caso particular, puede devolver una referencia a y. Hmm ... Pero estoy de acuerdo, sería extraño.
Yola

1
@ Mr.TAMER: Prefiero profundizar en el estándar. : <
Xeo

3
@Yola: Dado que los tipos son un concepto de tiempo de compilación en C ++, el valor de retorno real de la expresión no importa.
Xeo

1
No se devuelve una referencia, se obtiene el valor.
Suma

1
@Xeo: Sin embargo, no está en terminología de C ++;)
Sebastian Mach

19

No puede devolver un valor l ya que tendrá que promover implícitamente el tipo de xpara que coincida con el tipo de y(ya que ambos lados de :no son del mismo tipo), y con eso tiene que crear un temporal.


¿Qué dice el estándar? ( n1905 )

Expresiones 5.17 Operadores de asignación y asignación compuesta

5.17 / 3

Si el segundo y el tercer operando tienen tipos diferentes, y cualquiera de ellos tiene un tipo de clase (posiblemente calificado para cv), se intenta convertir cada uno de esos operandos al tipo del otro. El proceso para determinar si una expresión de operando E1 de tipo T1 se puede convertir para que coincida con una expresión de operando E2 de tipo T2 se define de la siguiente manera:

- Si E2 es un valor l: E1 se puede convertir para que coincida con E2 si E1 se puede convertir implícitamente (cláusula 4) al tipo “referencia a T2”, sujeto a la restricción de que en la conversión la referencia debe unirse directamente (8.5.3 ) a E1.

- Si E2 es un valor r, o si la conversión anterior no se puede hacer:

- si E1 y E2 tienen un tipo de clase, y los tipos de clase subyacentes son iguales o uno es una clase base del otro: E1 se puede convertir para que coincida con E2 si la clase de T2 es del mismo tipo o una clase base de , la clase de T1 y la calificación cv de T2 es la misma calificación cv o una calificación cv mayor que la calificación cv de T1. Si se aplica la conversión, E1 se cambia a un valor de tipo T2 que todavía se refiere al objeto de la clase fuente original (o al subobjeto apropiado del mismo). [ Nota: es decir, no se realiza ninguna copia. - nota final ] copia-inicializando un temporal de tipo T2 de E1 y usando ese temporal como el operando convertido.

De lo contrario (es decir, si E1o E2 tiene un tipo que no es de clase, o si ambos tienen tipos de clase pero las clases subyacentes no son las mismas o una clase base de la otra): E1 se puede convertir para que coincida con E2 si E1 puede ser se convirtió implícitamente al tipo que tendría la expresión E2 si E2 se convirtiera a un valor r (o el tipo que tiene, si E2 es un valor r).

Usando este proceso, se determina si el segundo operando se puede convertir para que coincida con el tercer operando, y si el tercer operando se puede convertir para que coincida con el segundo operando. Si ambos se pueden convertir, o uno se puede convertir pero la conversión es ambigua, el programa está mal formado. Si ninguno de los dos se puede convertir, los operandos no se modifican y se realiza una verificación adicional como se describe a continuación. Si es posible exactamente una conversión, esa conversión se aplica al operando elegido y el operando convertido se usa en lugar del operando original para el resto de esta sección.


5.17 / 4

Si el segundo y tercer operandos son valores y tienen el mismo tipo, el resultado es de ese tipo y es un valor l y es un campo de bits si el segundo o el tercer operando es un campo de bits, o si ambos son bits- campos.


5.17 / 5

De lo contrario, el resultado es un valor r. Si el segundo y el tercer operandos no tienen el mismo tipo, y alguno de ellos tiene (posiblemente calificado por cv), la resolución de sobrecarga se usa para determinar las conversiones (si las hay) que se aplicarán a los operandos (13.3.1.2, 13.6) . Si la resolución de sobrecarga falla, el programa está mal formado. De lo contrario, se aplican las conversiones así determinadas, y los operandos convertidos se usan en lugar de los operandos originales para el resto de esta sección.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.