Implicit conversions
Las conversiones implícitas se realizan cuando una expresión de algún tipo
T1
se utiliza en un contexto que no acepta ese tipo, pero acepta algún otro tipo
T2
; en particular:
-
cuando la expresión se utiliza como argumento al llamar a una función declarada con
T2como parámetro; -
cuando la expresión se utiliza como operando con un operador que espera
T2; -
cuando se inicializa un nuevo objeto de tipo
T2, incluyendo la sentenciareturnen una función que devuelveT2; -
cuando la expresión se utiliza en una sentencia
switch
(
T2es tipo integral); -
cuando la expresión se utiliza en una sentencia
if
o un bucle (
T2es bool ).
El programa está bien formado (compila) solo si existe una secuencia de
conversión implícita
inequívoca de
T1
a
T2
.
Si hay múltiples sobrecargas de la función u operador que se está llamando, después de construir la secuencia de conversión implícita desde
T1
a cada
T2
disponible,
las reglas de resolución de sobrecarga
deciden qué sobrecarga se compila.
Nota: en expresiones aritméticas, el tipo de destino para las conversiones implícitas en los operandos de operadores binarios se determina mediante un conjunto separado de reglas: usual arithmetic conversions .
Contenidos |
Orden de las conversiones
La secuencia de conversión implícita consiste en lo siguiente, en este orden:
Al considerar el argumento para un constructor o para una función de conversión definida por el usuario, solo se permite una secuencia de conversión estándar (de lo contrario, las conversiones definidas por el usuario podrían encadenarse efectivamente). Al convertir de un tipo no-clase a otro tipo no-clase, solo se permite una secuencia de conversión estándar.
Una secuencia de conversión estándar consta de lo siguiente, en este orden:
- lvalue-to-rvalue conversion ,
- array-to-pointer conversion , y
- function-to-pointer conversion ;
|
3)
cero o una
conversión de puntero a función
;
|
(since C++17) |
Una conversión definida por el usuario consiste en cero o un constructor de conversión de un solo argumento no explícito o una llamada a función de conversión no explícita conversion function .
Se dice que una expresión
e
es
implícitamente convertible a
T2
si y solo si
T2
puede ser
copy-initialized
desde
e
, es decir, la declaración
T2 t
=
e
;
está bien formada (puede compilarse), para algún
t
temporal inventado. Nótese que esto es diferente de la
direct initialization
(
T2 t
(
e
)
), donde se considerarían adicionalmente constructores explícitos y funciones de conversión.
Conversiones contextuales
|
En los siguientes contextos, se espera el tipo bool y se realiza la conversión implícita si la declaración bool t ( e ) ; es válida (es decir, una función de conversión explícita como explicit T :: operator bool ( ) const ; se considera). Dicha expresión e se dice que está contextualmente convertida a bool .
|
(desde C++11) |
En los siguientes contextos, se espera un tipo específico del contexto
T
, y la expresión
e
de tipo clase
E
solo está permitida si
|
(hasta C++14) |
|
(desde C++14) |
Tal expresión
e
se dice que está
convertida implícitamente contextualmente
al tipo especificado
T
.
Nótese que las funciones de conversión explícitas no se consideran, aunque sí se consideran en conversiones contextuales a
bool
.
(desde C++11)
-
el argumento de la
delete-expression
(
Tes cualquier tipo de puntero a objeto); -
expresión constante integral
, donde se utiliza una clase literal (
Tes cualquier tipo integral o de enumeración no acotada, la función de conversión definida por el usuario seleccionada debe ser constexpr ); -
la expresión de control de la sentencia
switch(Tes cualquier tipo integral o de enumeración).
#include <cassert> template<typename T> class zero_init { T val; public: zero_init() : val(static_cast<T>(0)) {} zero_init(T val) : val(val) {} operator T&() { return val; } operator T() const { return val; } }; int main() { zero_init<int> i; assert(i == 0); i = 7; assert(i == 7); switch (i) {} // error hasta C++14 (más de una función de conversión) // OK desde C++14 (ambas funciones convierten al mismo tipo int) switch (i + 0) {} // siempre correcto (conversión implícita) }
Transformaciones de valores
Las transformaciones de valor son conversiones que cambian la categoría de valor de una expresión. Ocurren cada vez que una expresión aparece como operando de un operador que espera una expresión de una categoría de valor diferente:
- Siempre que un glvalue aparece como operando de un operador que requiere un prvalue para ese operando, las conversiones estándar lvalue-to-rvalue , array-to-pointer , o function-to-pointer se aplican para convertir la expresión a un prvalue.
|
(since C++17) |
Conversión de lvalue a rvalue
Un
lvalue
(hasta C++11)
Un
glvalue
(desde C++11)
de cualquier tipo no-función, no-array
T
puede convertirse implícitamente a
un
rvalue
(hasta C++11)
un
prvalue
(desde C++11)
:
-
Si
Tno es un tipo clase, el tipo del rvalue (until C++11) prvalue (since C++11) es la versión sin calificadores cv deT. -
En caso contrario, el tipo del
rvalue
(until C++11)
prvalue
(since C++11)
es
T.
Si una conversión de lvalue a rvalue de un tipo incompleto es requerida por un programa, ese programa está mal formado.
Dado el objeto al cual la lvalue (until C++11) glvalue (since C++11) se refiere como obj :
|
(hasta C++11) | ||||
|
(desde C++11) |
Esta conversión modela el acto de leer un valor desde una ubicación de memoria hacia un registro de la CPU.
Conversión de array a puntero
Un
lvalue
o
rvalue
de tipo "array de
N
T
" o "array de límite desconocido de
T
" puede convertirse implícitamente a un
prvalue
de tipo "puntero a
T
".
Si el array es un prvalue,
ocurre materialización temporal
.
(desde C++17)
El puntero resultante se refiere al primer elemento del array (ver
Decaimiento de array a puntero
para más detalles).
Conversión de función a puntero
Un lvalue de tipo función puede convertirse implícitamente a un prvalue puntero a esa función . Esto no se aplica a funciones miembro no estáticas porque no existen lvalues que se refieran a funciones miembro no estáticas.
Materialización temporal
Un
prvalue
de cualquier tipo completo
Si
struct S { int m; }; int i = S().m; // member access expects glvalue as of C++17; // S() prvalue is converted to xvalue La materialización temporal ocurre en las siguientes situaciones:
Nótese que la materialización temporal no ocurre al inicializar un objeto desde un prvalue del mismo tipo (mediante inicialización directa o inicialización por copia ): dicho objeto se inicializa directamente desde el inicializador. Esto garantiza la "elisión de copia garantizada". |
(desde C++17) |
Promoción integral
prvalues de tipos integrales pequeños (como char ) y tipos de enumeración no delimitados pueden convertirse en prvalues de tipos integrales más grandes (como int ). En particular, los operadores aritméticos no aceptan tipos más pequeños que int como argumentos, y las promociones integrales se aplican automáticamente después de la conversión de lvalue-a-rvalue, si es aplicable. Esta conversión siempre preserva el valor.
Las siguientes conversiones implícitas en esta sección se clasifican como integral promotions .
Tenga en cuenta que para un tipo de origen dado, el tipo de destino de la promoción integral es único, y todas las demás conversiones no son promociones. Por ejemplo, la resolución de sobrecarga elige char -> int (promoción) sobre char -> short (conversión).
Promoción de tipos integrales
Un prvalue de tipo bool puede convertirse en un prvalue de tipo int , donde false se convierte en 0 y true se convierte en 1 .
Para un prvalue
val
de un tipo integral
T
excepto
bool
:
- val puede convertirse a un prvalue de tipo int si int puede representar todos los valores del campo de bits;
- de lo contrario, val puede convertirse a unsigned int si unsigned int puede representar todos los valores del campo de bits;
- de lo contrario, val puede convertirse de acuerdo con las reglas especificadas en el punto (3).
-
si
Tes char8_t , (desde C++20) char16_t , char32_t o (desde C++11) wchar_t , val puede convertirse según las reglas especificadas en el punto (3); -
en caso contrario, si el
rango de conversión entera
de
Tes menor que el rango de int :
-
-
val
puede convertirse a un prvalue de tipo
int
si
int
puede representar todos los valores de
T; - en caso contrario, val puede convertirse a un prvalue de tipo unsigned int .
-
val
puede convertirse a un prvalue de tipo
int
si
int
puede representar todos los valores de
T
es uno de los tipos de carácter dados),
val
puede convertirse a un prvalue del primero de los siguientes tipos que pueda representar todos los valores de su tipo subyacente:
-
- int
- unsigned int
- long
- unsigned long
|
(desde C++11) |
Promoción desde tipos de enumeración
Un prvalue de un tipo de enumeración no delimitada enumeration cuyo tipo subyacente no está fijo puede convertirse a un prvalue del primer tipo de la siguiente lista capaz de contener su rango completo de valores:
- int
- unsigned int
- long
- unsigned long
|
(desde C++11) |
|
Un prvalue de un tipo de enumeración no acotado cuyo tipo subyacente está fijo puede convertirse a su tipo subyacente. Además, si el tipo subyacente también está sujeto a promoción integral, al tipo subyacente promocionado. La conversión al tipo subyacente no promocionado es mejor para los propósitos de resolución de sobrecarga . |
(since C++11) |
Promoción de punto flotante
Un prvalue de tipo float puede convertirse a un prvalue de tipo double . El valor no cambia.
Esta conversión se denomina floating-point promotion .
Conversiones numéricas
A diferencia de las promociones, las conversiones numéricas pueden cambiar los valores, con posible pérdida de precisión.
Conversiones integrales
Un prvalue de un tipo entero o de un tipo de enumeración sin ámbito puede convertirse a cualquier otro tipo entero. Si la conversión está listada bajo promociones integrales, es una promoción y no una conversión.
-
Si el tipo de destino es sin signo, el valor resultante es el valor sin signo más pequeño igual al valor de origen
módulo
2
n
donde n es el número de bits utilizados para representar el tipo de destino.
-
- Es decir, dependiendo de si el tipo de destino es más amplio o más estrecho, los enteros con signo se extienden con signo [1] o se truncan y los enteros sin signo se extienden con ceros o se truncan respectivamente.
-
Si el tipo de destino es con signo, el valor no cambia si el entero fuente puede representarse en el tipo de destino. De lo contrario, el resultado es
definido por la implementación
(hasta C++20)
el valor único del tipo de destino igual al valor fuente módulo
2
n
donde n es el número de bits utilizados para representar el tipo de destino (desde C++20) (nótese que esto es diferente del desbordamiento aritmético de enteros con signo , que es indefinido). - Si el tipo fuente es bool , el valor false se convierte a cero y el valor true se convierte al valor uno del tipo de destino (nótese que si el tipo de destino es int , esto es una promoción entera, no una conversión entera).
- Si el tipo de destino es bool , esto es una conversión booleana (ver más abajo).
- ↑ Esto solo aplica si la aritmética es complemento a dos, lo cual solo es requerido para los tipos de enteros de ancho exacto . Sin embargo, nótese que actualmente todas las plataformas con un compilador de C++ utilizan aritmética de complemento a dos.
Conversiones de punto flotante
|
Un prvalue de un tipo de punto flotante puede convertirse en un prvalue de cualquier otro tipo de punto flotante. |
(until C++23) |
|
Un prvalue de un tipo de punto flotante puede convertirse en un prvalue de cualquier otro tipo de punto flotante con un rango de conversión de punto flotante mayor o igual. Un prvalue de un tipo estándar de punto flotante puede convertirse en un prvalue de cualquier otro tipo estándar de punto flotante.
|
(since C++23) |
Si la conversión se enumera bajo promociones de punto flotante, es una promoción y no una conversión.
- Si el valor fuente puede representarse exactamente en el tipo destino, no cambia.
- Si el valor fuente está entre dos valores representables del tipo destino, el resultado es uno de esos dos valores (está definido por la implementación cuál, aunque si se admite aritmética IEEE, el redondeo por defecto es al más cercano ).
- En caso contrario, el comportamiento es indefinido.
Conversiones flotante-integral
Un prvalue de tipo punto flotante puede convertirse a un prvalue de cualquier tipo entero. La parte fraccionaria se trunca, es decir, la parte fraccionaria se descarta.
- Si el valor truncado no puede caber en el tipo de destino, el comportamiento es indefinido (incluso cuando el tipo de destino es unsigned, la aritmética modular no se aplica).
- Si el tipo de destino es bool , esta es una conversión booleana (ver abajo ).
Un prvalue de tipo entero o de enumeración sin ámbito puede convertirse en un prvalue de cualquier tipo de punto flotante. El resultado es exacto si es posible.
- Si el valor puede caber en el tipo de destino pero no puede representarse exactamente, está definido por la implementación si se seleccionará el valor representable más cercano superior o el más cercano inferior, aunque si se admite aritmética IEEE, el redondeo por defecto es al más cercano .
- Si el valor no puede caber en el tipo de destino, el comportamiento es indefinido.
- Si el tipo de origen es bool , el valor false se convierte a cero, y el valor true se convierte a uno.
Conversiones de punteros
Una constante de puntero nulo puede convertirse a cualquier tipo de puntero, y el resultado es el valor de puntero nulo de ese tipo. Dicha conversión (conocida como conversión de puntero nulo ) está permitida para convertir a un tipo calificado cv como una conversión única, es decir, no se considera una combinación de conversiones numéricas y calificadoras.
Un
prvalue
puntero a cualquier tipo de objeto (opcionalmente calificado con cv)
T
puede convertirse en un prvalue puntero a
void
(idénticamente calificado con cv). El puntero resultante representa la misma ubicación en memoria que el valor del puntero original.
- Si el puntero original es un valor de puntero nulo, el resultado es un valor de puntero nulo del tipo de destino.
Un prvalue
ptr
de tipo "puntero a (posiblemente calificado-cv)
Derived
" puede convertirse en un prvalue de tipo "puntero a (posiblemente calificado-cv)
Base
", donde
Base
es una
clase base
de
Derived
, y
Derived
es un tipo de clase
completa
. Si
Base
es inaccesible o ambigua, el programa está mal formado.
- Si ptr es un valor de puntero nulo, el resultado también es un valor de puntero nulo.
-
De lo contrario, si
Basees una clase base virtual deDerivedy ptr no apunta a un objeto cuyo tipo sea similar aDerivedy que esté dentro de su tiempo de vida o dentro de su período de construcción o destrucción, el comportamiento es indefinido. - De lo contrario, el resultado es un puntero al subobjeto de la clase base del objeto de la clase derivada.
Conversiones de puntero a miembro
Una constante de puntero nulo puede convertirse a cualquier tipo puntero-a-miembro, y el resultado es el valor de puntero a miembro nulo de ese tipo. Dicha conversión (conocida como conversión de puntero a miembro nulo ) está permitida para convertir a un tipo calificado-cv como una conversión única, es decir, no se considera una combinación de conversiones numéricas y calificadoras.
Un
prvalue
de tipo "puntero a miembro de
Base
de tipo (posiblemente calificado-cv)
T
" puede convertirse en un prvalue de tipo "puntero a miembro de
Derived
de tipo (idénticamente calificado-cv)
T
", donde
Base
es una clase base de
Derived
, y
Derived
es un tipo de clase completo. Si
Base
es una base inaccesible, ambigua o virtual de
Derived
o es una base de alguna base virtual intermedia de
Derived
, el programa está mal formado.
-
Si
Derivedno contiene el miembro original y no es una clase base de la clase que contiene el miembro original, el comportamiento es indefinido. -
De lo contrario, el puntero resultante puede ser desreferenciado con un objeto
Derived, y accederá al miembro dentro del subobjeto baseBasede ese objetoDerived.
Conversiones booleanas
Un prvalue de tipos enteros, de punto flotante, enumeración sin ámbito, puntero y puntero-a-miembro puede convertirse en un prvalue de tipo bool .
El valor cero (para tipos integrales, de punto flotante y enumeraciones no delimitadas) y los valores de puntero nulo y puntero-a-miembro nulo se convierten en false . Todos los demás valores se convierten en true .
|
En el contexto de una inicialización directa , un objeto bool puede ser inicializado desde un prvalue de tipo std::nullptr_t , incluyendo nullptr . El valor resultante es false . Sin embargo, esto no se considera una conversión implícita. |
(desde C++11) |
Conversiones de calificación
En términos generales:
-
Un
prvalue
de tipo puntero a tipo
calificado-cv
Tpuede convertirse en un prvalue puntero al mismo tipoTmás calificado-cv (en otras palabras, se puede añadir constancia y volatilidad). -
Un prvalue de tipo puntero a miembro de tipo calificado-cv
Ten claseXpuede convertirse en un prvalue puntero a miembro de tipo más calificado-cvTen claseX.
La definición formal de "qualification conversion" se proporciona a continuación .
Tipos similares
Informalmente, dos tipos son similares si, ignorando la calificación cv de nivel superior:
- son del mismo tipo; o
- ambos son punteros, y los tipos apuntados son similares; o
- ambos son punteros a miembro de la misma clase, y los tipos de los miembros apuntados son similares; o
- ambos son arreglos y los tipos de elementos del arreglo son similares.
Por ejemplo:
- const int * const * y int ** son similares;
- int ( * ) ( int * ) y int ( * ) ( const int * ) no son similares;
- const int ( * ) ( int * ) y int ( * ) ( int * ) no son similares;
- int ( * ) ( int * const ) y int ( * ) ( int * ) son similares (son el mismo tipo);
- std:: pair < int , int > y std:: pair < const int , int > no son similares.
Formalmente, la similitud de tipos se define en términos de descomposición de calificación.
Una
descomposición de calificaciones
de un tipo
T
es una secuencia de componentes
cv_i
y
P_i
tal que
T
es "
cv_0 P_0 cv_1 P_1 ... cv_n−1 P_n−1 cv_n U
" para
n
no negativo, donde
-
cada
cv_ies un conjunto de const y volatile , y -
cada
P_ies
-
- “puntero a”,
-
“puntero a miembro de la clase
C_ide tipo”, - “arreglo de N_i ”, o
- “arreglo de límite desconocido de”.
Si
P_i
designa un array, los calificadores cv
cv_i+1
en el tipo del elemento también se toman como los calificadores cv
cv_i
del array.
// T es "puntero a puntero a const int", tiene 3 descomposiciones de calificación: // n = 0 -> cv_0 está vacío, U es "puntero a puntero a const int" // n = 1 -> cv_0 está vacío, P_0 es "puntero a", // cv_1 está vacío, U es "puntero a const int" // n = 2 -> cv_0 está vacío, P_0 es "puntero a", // cv_1 está vacío, P_1 es "puntero a", // cv_2 es "const", U es "int" using T = const int**; // sustituir cualquiera de los siguientes tipos en U da una de las descomposiciones: // U = U0 -> la descomposición con n = 0: U0 // U = U1 -> la descomposición con n = 1: puntero a [U1] // U = U2 -> la descomposición con n = 2: puntero a [puntero a [const U2]] using U2 = int; using U1 = const U2*; using U0 = U1*;
Dos tipos
T1
y
T2
son
similares
si existe una descomposición de calificación para cada uno de ellos, donde se satisfacen todas las siguientes condiciones para las dos descomposiciones de calificación:
- Tienen el mismo n .
-
Los tipos denotados por
Uson los mismos. -
Los correspondientes componentes
P_ison los mismos o uno es "array de N_i " y el otro es "array de límite desconocido de" (desde C++20) para todo i .
// la descomposición de calificaciones con n = 2: // puntero a [puntero volátil a [const int]] using T1 = const int* volatile *; // la descomposición de calificaciones con n = 2: // puntero const a [puntero a [int]] using T2 = int** const; // Para las dos descomposiciones de calificaciones anteriores // aunque cv_0, cv_1 y cv_2 son todos diferentes, // tienen el mismo n, U, P_0 y P_1, // por lo tanto los tipos T1 y T2 son similares.
Combinación de calificadores cv
En la descripción a continuación, la descomposición de calificación más larga del tipo
Tn
se denota como
Dn
, y sus componentes se denotan como
cvn_i
y
Pn_i
.
|
Una expresión prvalue de tipo
El
tipo de calificación combinada
de dos tipos
|
(hasta C++20) |
|
El
tipo de calificación combinada
de dos tipos
Un prvalue de tipo
|
(desde C++20) |
// descomposición de calificación más larga de T1 (n = 2): // puntero a [puntero a [char]] using T1 = char**; // descomposición de calificación más larga de T2 (n = 2): // puntero a [puntero a [const char]] using T2 = const char**; // Determinando los componentes cv3_i y T_i de D3 (n = 2): // cv3_1 = vacío (unión de cv1_1 vacío y cv2_1 vacío) // cv3_2 = "const" (unión de cv1_2 vacío y "const" cv2_2) // P3_0 = "puntero a" (sin array de límite desconocido, usar P1_0) // P3_1 = "puntero a" (sin array de límite desconocido, usar P1_1) // Todos los componentes excepto cv_2 son iguales, cv3_2 es diferente de cv1_2, // por lo tanto agregar "const" a cv3_k para cada k en [1, 2): cv3_1 se convierte en "const". // T3 es "puntero a puntero const a const char", es decir, const char* const *. using T3 = /* el tipo combinado por calificación de T1 y T2 */; int main() { const char c = 'c'; char* pc; T1 ppc = &pc; T2 pcc = ppc; // Error: T3 no es igual a T2 sin calificación cv, // no hay conversión implícita. *pcc = &c; *pc = 'C'; // Si se permite la asignación errónea anterior, // el objeto const "c" podría ser modificado. }
Tenga en cuenta que en el lenguaje de programación C, const / volatile solo puede agregarse al primer nivel:
char** p = 0; char * const* p1 = p; // Correcto en C y C++ const char* const * p2 = p; // error en C, correcto en C++
Conversiones de punteros a función
void (*p)(); void (**pp)() noexcept = &p; // error: cannot convert to pointer to noexcept function struct S { typedef void (*p)(); operator p(); }; void (*q)() noexcept = S(); // error: cannot convert to pointer to noexcept function |
(desde C++17) |
El problema del booleano seguro
Hasta C++11, diseñar una clase que debiera ser utilizable en contextos booleanos (por ejemplo, if ( obj ) { ... } ) presentaba un problema: dada una función de conversión definida por el usuario, como T :: operator bool ( ) const ; , la secuencia de conversión implícita permitía una secuencia de conversión estándar adicional después de esa llamada a función, lo que significa que el bool resultante podría convertirse a int , permitiendo código como obj << 1 ; o int i = obj ; .
Una solución temprana para esto puede verse en std::basic_ios , que inicialmente define operator void * , de modo que código como if ( std:: cin ) { ... } compila porque void * es convertible a bool , pero int n = std:: cout ; no compila porque void * no es convertible a int . Esto todavía permite que código sin sentido como delete std:: cout ; pueda compilar.
Muchas bibliotecas de terceros anteriores a C++11 fueron diseñadas con una solución más elaborada, conocida como el Safe Bool idiom . std::basic_ios también permitía este idiom mediante LWG issue 468 , y operator void * fue reemplazado (ver notas ).
Desde C++11, la conversión explícita a bool también puede utilizarse para resolver el problema del bool seguro.
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| CWG 170 | C++98 |
el comportamiento de las conversiones de puntero-a-miembro no estaba claro
si la clase derivada no tiene el miembro original |
aclarado |
| CWG 172 | C++98 | el tipo de enumeración se promovía basándose en su tipo subyacente | basándose en su rango de valores en su lugar |
|
CWG 330
( N4261 ) |
C++98 |
la conversión de
double
*
const
(
*
p
)
[
3
]
a double const * const ( * p ) [ 3 ] era inválida |
se hizo válida |
| CWG 519 | C++98 |
los valores de puntero nulo no estaban garantizados de
preservarse al convertir a otro tipo de puntero |
siempre preservados |
| CWG 616 | C++98 |
el comportamiento de la conversión de lvalue a rvalue de
cualquier objeto no inicializado y objetos puntero con valores inválidos siempre estaba indefinido |
se permite el
unsigned
char
indeterminado; el uso de punteros inválidos está definido por la implementación |
| CWG 685 | C++98 |
el tipo subyacente de un tipo de enumeración no era
priorizado en la promoción integral si está fijo |
priorizado |
| CWG 707 | C++98 |
la conversión de entero a punto flotante
tenía comportamiento definido en todos los casos |
el comportamiento es indefinido si
el valor que se convierte está fuera del rango de destino |
| CWG 1423 | C++11 |
std::nullptr_t
era convertible a
bool
tanto en inicialización directa como en inicialización por copia |
solo inicialización directa |
| CWG 1773 | C++11 |
una expresión de nombre que aparece en una expresión potencialmente evaluada
tal que el objeto nombrado no es odr-used podría aún ser evaluado durante una conversión lvalue-to-rvalue |
no evaluado |
| CWG 1781 | C++11 |
std::nullptr_t
a
bool
se consideraba una conversión implícita
aunque solo es válida para inicialización directa |
ya no se considera
una conversión implícita |
| CWG 1787 | C++98 |
el comportamiento de leer desde un valor indeterminado
unsigned char almacenado en caché en un registro no estaba definido |
se definió correctamente |
| CWG 1981 | C++11 | conversiones contextuales consideradas funciones de conversión explícitas | no considerado |
| CWG 2140 | C++11 |
no estaba claro si las conversiones de lvalue a rvalue desde
std::nullptr_t lvalues obtienen estos lvalues de la memoria |
no se obtienen |
| CWG 2310 | C++98 |
para conversiones de puntero de derivado-a-base y
conversiones de puntero-a-miembro de base-a-derivado, el tipo de clase derivada podría estar incompleto |
debe estar completo |
| CWG 2484 | C++20 |
char8_t
y
char16_t
tenían diferentes estrategias de
promoción integral, pero pueden acomodar ambas |
char8_t
debería promocionarse
de la misma manera que char16_t |
| CWG 2485 | C++98 | las promociones integrales que involucran campos de bits no estaban bien especificadas | se mejoró la especificación |
| CWG 2813 | C++23 |
la materialización temporal ocurriría cuando se invoca una
función miembro de objeto explícito de un prvalue de clase |
no ocurrirá
en este caso |
| CWG 2861 | C++98 |
un puntero a un objeto de acceso restringido por tipo podría ser
convertido a un puntero a un subobjeto de clase base |
el comportamiento es
indefinido en este caso |
| CWG 2879 | C++17 |
la conversión de materialización temporal se aplicó en prvalue
como operando de un operador que espera glvalue |
no aplicado en algunos casos |
| CWG 2899 | C++98 |
las conversiones de lvalue a rvalue podrían aplicarse a lvalues
que designan objetos con representaciones de valor inválidas |
el comportamiento es
indefinido en este caso |
| CWG 2901 | C++98 |
el resultado de la conversión de lvalue a rvalue desde un
unsigned
int
lvalue que se refiere a un objeto int con valor - 1 era poco claro |
aclarado |
Véase también
-
const_cast -
static_cast -
dynamic_cast -
reinterpret_cast - conversión explícita
- conversión definida por el usuario
|
Documentación de C
para
Conversiones implícitas
|