Conversiones aritméticas habituales
Muchos operadores binarios que esperan operandos de tipo aritmético o enumeración provocan conversiones y producen tipos de resultados de forma similar. El objetivo es producir un tipo común, que también es el tipo del resultado. Este patrón se denomina conversiones aritméticas habituales.
Contenido |
[editar]Definición
Las conversiones aritméticas habituales se definen de la siguiente manera:
[editar]Etapa 1
Aplica conversión de l-valor a r-valor a ambos operandos, los pr-valores resultantes se utilizan en lugar de los operandos originales para el resto del proceso.
[editar]Etapa 2
| (desde C++11) |
[editar]Etapa 3
| (desde C++26) |
[editar]Etapa 4
- Si alguno de los operandos es de tipo de punto flotante, se aplican las siguientes reglas:
- Si ambos operandos tienen el mismo tipo, no se realizará ninguna conversión adicional.
- De lo contrario, si uno de los operandos es de un tipo que no es de punto flotante, ese operando se convierte al tipo del otro operando.
- De lo contrario, si los rangos de conversión de punto flotante de los tipos de los operandos están ordenados pero no son iguales, entonces el operando del tipo con el rango de conversión de punto flotante menor se convierte al tipo del otro operando.
| (desde C++23) |
- De lo contrario, ambos operandos son de tipo entero, se procede a la siguiente etapa.
[editar]Etapa 5
Ambos operandos se convierten a un tipo común C
. Dados los tipos T1
y T2
como el tipo promocionado (según las reglas de promociones de enteros) de los operandos, se aplican las siguientes reglas para determinar C
:
- Si
T1
yT2
son del mismo tipo,C
es ese tipo. - De lo contrario, si
T1
yT2
son ambos de tipo entero con signo o ambos de tipo entero sin signo,C
es el tipo de rango de conversión de enteros mayor. - De lo contrario, un tipo entre
T1
yT2
es un tipo de entero con signoS
, el otro tipo es un tipo entero sin signoU
. Se aplican las siguientes reglas:
- Si el rango de conversión de enteros de
U
es mayor o igual que el rango de conversión de enteros deS
,C
esU
. - De lo contrario, si
S
puede representar todos los valores deU
,C
esS
. - De lo contrario,
C
es el tipo entero sin signo correspondiente aS
.
- Si el rango de conversión de enteros de
Si un operando es de tipo enumeración y el otro operando es de un tipo enumeración diferente o un tipo de punto flotante, este comportamiento queda obsoleto. | (desde C++20) (hasta C++26) |
[editar]Rango de conversión de enteros
Cada tipo entero tiene un rango de conversión de enteros definido de la siguiente manera:
- No hay dos tipos enteros con signo distintos de char y signedchar (si char tiene signo) que tengan el mismo rango, incluso si tienen la misma representación.
- El rango de un tipo entero con signo es mayor que el rango de cualquier tipo entero con signo con un ancho menor.
- Los rangos de los siguientes tipos enteros disminuyen en orden:
| (desde C++11) |
- long
- int
- short
- signedchar
- El rango de cualquier tipo entero sin signo es igual al rango del tipo entero con signo correspondiente.
| (desde C++11) |
- El rango de bool es menor que el rango de todos los tipos enteros estándar.
- Los rangos de los tipos de caracteres codificados (char, char8_t(desde C++20), char16_t, char32_t,(desde C++11) y wchar_t) son iguales a los rangos de sus tipos subyacentes, lo que significa:
- El rango de char es igual al rango de signedchar y unsignedchar.
| (desde C++20) |
| (desde C++11) |
- El rango de wchar_t es igual al rango de su tipo subyacente definido por la implementación.
| (desde C++11) |
- Para todos los tipos enteros
T1
,T2
yT3
, siT1
tiene mayor rango queT2
yT2
tiene mayor rango queT3
, entoncesT1
tiene mayor rango queT3
.
El rango de conversión de enteros también se utiliza en la definición de la promoción de enteros.
[editar]Rango y subrango de conversión de punto flotante
[editar]Rango de conversión de punto flotante
Cada tipo de punto flotante tiene un rango de conversión de punto flotante definido de la siguiente manera:
- Los rangos de los tipos de punto flotante estándar disminuyen en orden:
- longdouble
- double
- float
| (desde C++23) |
Subrango de conversión de punto flotanteLos tipos de punto flotante que tienen rangos de conversión de punto flotante iguales se ordenan por subrango de conversión de punto flotante. El subrango forma un orden total entre los tipos con rangos iguales. Los tipos | (desde C++23) |
[editar]Uso
El rango y subrango de conversión de punto flotante también se utilizan para
- determinar si una conversión entre diferentes tipos de punto flotante puede ser implícita o es una conversión estrechante,
- distinguir las secuencias de conversión en la resolución de sobrecarga,
|
- determinar si el constructor de conversión de std::complex es explícito, o
- determinar el tipo de punto flotante común si los argumentos de diferentes tipos de punto flotante se pasan a funciones matemáticas comunes o especiales.
[editar]Informes de defectos
Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.
ID | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
---|---|---|---|
CWG 1642 | C++98 | Las conversiones aritméticas habituales pueden involucrar l-valores. | Aplica primero las conversiones de l-valor a r-valor. |
CWG 2528 | C++20 | La comparación de tres vías entre unsignedchar y unsignedint está mal formada debido a la promoción de enteros intermedia.[1] | Determina el tipo común basado en los tipos promocionados, sin promocionar realmente los operandos.[2] |
CWG 2892 | C++98 | Cuando ambos operandos son del mismo tipo de punto flotante, el significado de “no se necesita ninguna conversión adicional” no estaba claro. | Se cambió a “no se realizará ninguna conversión adicional”. |
- ↑Antes de la resolución, unsignedchar se promueve a int al comienzo de la etapa 5, luego se convierte a unsignedint. Sin embargo, la última conversión es restrictiva, lo que hace que la comparación de tres vías esté mal formada.
- ↑Después de la resolución, el tipo común sigue siendo unsignedint. La diferencia es que unsignedchar se convierte directamente en unsignedint sin la promoción de enteros intermedia. La conversión no es restrictiva y, por lo tanto, la comparación de tres vías está bien formada.