Espacios de nombres
Variantes
Acciones

Conversión de tipo explícita

De cppreference.com
< cpp‎ | language
 
 
 
 

Convierte entre tipos utilizando una combinación de conversiones explícitas e implícitas.

Contenido

[editar] Sintaxis

( tipo-de-destino ) expresión (1)
tipo-de-destino ( lista-de-expresiones (opcional) ) (2)
tipo-de-destino { lista-de-expresiones (opcional) } (3) (desde C++11)
nombre-de-plantilla ( lista-de-expresiones (opcional) ) (4) (desde C++17)
nombre-de-plantilla { lista-de-expresiones (opcional) } (5) (desde C++17)
auto ( expresión ) (6) (desde C++23)
auto { expresión } (7) (desde C++23)

Devuelve un valor de tipo tipo-de-destino.

[editar] Explicación

1) Cuando se encuentra con la expresión de conversión estilo C, el compilador intenta interpretarla como las siguientes expresiones, en este orden:
a) const_cast<tipo-de-destino>(expresión);
b) static_cast<tipo-de-destino>(expresión), con extensiones: se permite además convertir un puntero o referencia a una clase derivada a un puntero o referencia a una clase base inequívoca (y viceversa) incluso si la clase base es inaccesible (es decir, esta conversión ignora el especificador de herencia privada). Lo mismo se aplica a la conversión de puntero a miembro a un puntero a miembro de una base no virtual inequívoca;
c) una conversión static_cast (con extensiones) seguido de const_cast;
d) reinterpret_cast<tipo-de-destino>(expresión);
e) una conversión reinterpret_cast seguido de const_cast.
Se selecciona la primera opción que satisface los requisitos del operador de conversión respectivo, incluso si está mal formada (ver ejemplo). Si se utiliza static_cast seguido de const_cast y la conversión se puede interpretar de más de una manera como tal, la conversión está mal formada.
Además, se permite la notación de conversión de estilo C para convertir desde, hacia y entre punteros a tipos clase incompletos. Si tanto expresión como tipo-de-destino son punteros a tipos clase incompletos, no se especifica si se selecciona static_cast o reinterpret_cast.
2) La expresión de estilo de conversión funcional consiste en un especificador de tipo simple o un especificador typedef (en otras palabras, un nombre de tipo de una sola palabra, es decir, casos como unsigned int(expresión) e int*(expresión) no son válidos), seguido de una lista de expresiones separadas por comas entre paréntesis.
  • Si hay exactamente una expresión entre paréntesis, esta expresión de conversión es exactamente equivalente a la expresión de estilo de conversión C correspondiente.
  • Si hay más de una expresión o inicialización de lista entre llaves (desde C++11) entre paréntesis, tipo-de-destino debe ser una clase con un constructor declarado adecuadamente. Esta expresión es un pr-valor de tipo tipo-de-destino que designa un objeto temporal (hasta C++17)cuyo objeto resultado es (desde C++17) inicializado mediante inicialización directa con ( expresión-list ) como inicializador.
  • Si no hay expresión entre paréntesis: si tipo-de-destino nombra un tipo objeto array no completo, esta expresión es un pr-valor de tipo tipo-de-destino, que designa un (hasta C++17)temporal (desde C++17) cuyo objeto resultado es (posiblemente con calificadores agregados const volatile) de ese tipo. Si tipo-de-destino es un tipo objeto, el objeto es inicializado por valor. Si tipo-de-destino es (posiblemente calificado const volatile) void, la expresión es un pr-valor void sin un objeto resultado (desde C++17).
3) Un nombre de tipo de una sola palabra seguido de una lista de inicializadores entre llaves es un pr-valor del tipo especificado que designa un (hasta C++17)temporal cuyo objeto de resultado es (desde C++17) inicializado por inicialización de lista directa con { expresión-list } como inicializador. Si tipo-de-destino es (posiblemente calificado const volatile) void, la expresión es un void pr-valor without a result object (desde C++17). Esta es la única expresión de conversión que puede crear un array de tipo pr-valor. (hasta C++20)
4,5) Igual que (2,3), excepto que primero realiza deducción de argumentos de plantilla de clase.
6,7) El especificador auto se reemplaza con el tipo deducido de expresión. El resultado siempre es un pr-valor de un tipo objeto.

Como con todas las expresiones de conversión, el resultado es:

  • Un l-valor si tipo-de-destino es un tipo referencia a l-valor o un tipo referencia r-valor a función (desde C++11);
  • Un x-valor se tipo-de-destino es un tipo referencia r-valor a tipo objeto;
(desde C++11)
  • Un pr-valor en caso contrario.

[editar] Resolución de ambigüedades

[editar] Instrucción de declaración ambigua

En el caso de una ambigüedad entre una declaración de expresión con una expresión de conversión de estilo función como su subexpresión más a la izquierda y una declaración, la ambigüedad se resuelve tratándola como una declaración. Esta desambiguación es puramente sintáctica: no considera el significado de los nombres que aparecen en la declaración, salvo si son nombres de tipo:

struct M {};
struct L { L(M&); };
 
M n;
void f()
{
    M(m);    // declaración, equivalente a M m;
    L(n);    // declaración mal formada, equivalente a L n;
    L(l)(m); // todavía una declaración, equivalente a L l((m));
}

Sin embargo, si el declarador más externo en la instrucción de declaración ambigua tiene un tipo de retorno al final, la instrucción solo se tratará como una declaración si el tipo de retorno final comienza con auto:

struct M;
 
struct S
{
    S* operator()();
    int N;
    int M;
 
    void mem(S s)
    {
        auto(s)()->M; // expresión (S::M hides ::M), inválida antes de C++23
    }
};
 
void f(S s)
{
    {
        auto(s)()->N; // expresión, inválida antes de C++23
        auto(s)()->M; // declaración de función, equivalente a M s();
    }
    {
        S(s)()->N;    // expresión
        S(s)()->M;    // expresión
    }
}
(desde C++11)

[editar] Parámetro de función ambiguo

La ambigüedad anterior también puede ocurrir en el contexto de una declaración. En ese contexto, la elección es entre una declaración de objeto con una función de estilo de conversión como inicializador y una declaración que involucra un declarador de función con un conjunto redundante de paréntesis alrededor de un nombre de parámetro. La solución también es considerar cualquier construcción, como la posible declaración de parámetro, que podría ser una declaración como tal:

struct S
{
    S(int);
};
 
void foo(double a)
{
    S w(int(a)); // declaración de función: tiene un parámetro `a` de tipo int
    S x(int());  // declaración de función: tiene un parámetro sin nombre de tipo int(*)()
                 // que se ajusta desde int()
 
    // Formas de evitar ambigüedad:
    S y((int(a))); // declaración de objeto: extra par de paréntesis
    S y((int)a);   // declaración de objeto: conversión estilo C
    S z = int(a);  // declaración de objeto: no hay ambigüedad para esta sintaxis
}

Sin embargo, si el declarador más externo en la declaración de parámetro ambiguo tiene un tipo de retorno al final, la ambigüedad solo se resolverá tratándolo como una declaración si comienza con auto:

typedef struct BB { int C[2]; } *B, C;
 
void foo()
{
    S a(B()->C);    // declaración de objeto: B()->C no puede declarar un parámetro
    S b(auto()->C); // declaración de función: tiene un parámetro sin nombre de tipo C(*)()
                    // que está ajustado de C()
}
(desde C++11)

[editar] id-de-tipo ambiguo

Una ambigüedad puede surgir de la similitud entre una conversión de estilo de función y un id-de-tipo. La solución es que cualquier construcción que podría ser un id-de-tipo en su contexto sintáctico se considerará un id-de-tipo:

// `int()` y `int(unsigned(a))` pueden analizarse como id-de-tipo:
// `int()`            representa una función que devuelve int
//                    y no toma argumentos
// `int(unsigned(a))` representa una función que devuelve int
//                    y toma un argumento de tipo unsigned
void foo(signed char a)
{
    sizeof(int());            // id-de-tipo (mal formado)
    sizeof(int(a));           // expresión
    sizeof(int(unsigned(a))); // id-de-tipo (mal formado)
 
    (int()) + 1;            // id-de-tipo (mal formado)
    (int(a)) + 1;           // expresión
    (int(unsigned(a))) + 1; // id-de-tipo (mal formado)
}

Sin embargo, si el declarador-abstracto más externo en el id-de-tipo ambiguo tiene un tipo de retorno al final, la ambigüedad solo se resolverá tratándolo como un id-de-tipo si comienza con auto:

typedef struct BB { int C[2]; } *B, C;
 
void foo()
{
    sizeof(B()->C[1]);    // OK, sizeof(expresión)
    sizeof(auto()->C[1]); // ERROR: sizeof de una función que devuelve un array
}
(desde C++11)

[editar] Notas

Macro de prueba de característica Valor Estándar Comentario
__cpp_auto_cast 202110L (C++23) auto(x) y auto{x}

[editar] Ejemplo

#include <cassert>
#include <iostream>
 
double f = 3.14;
unsigned int n1 = (unsigned int)f; // conversión estilo C
unsigned int n2 = unsigned(f);     // conversión estilo función
 
class C1;
class C2;
C2* foo(C1* p)
{
    return (C2*)p; // convierte un tipo incompleto a otro tipo incompleto
}
 
void cpp23_decay_copy_demo()
{
    auto inc_print = [](int& x, const int& y)
    {
        ++x;
        std::cout << "x:" << x << ", y:" << y << '\n';
    };
 
    int p{1};
    inc_print(p, p); // imprime x:2 y:2, porque el parámetro `y` aquí es un alias de `p`
    int q{1};
    inc_print(q, auto{q}); // imprime x:2 y:1, auto{q} (C++23) convierte a pr-valor,
                           // entonces el parámetro `y` es una copia de `q` (no un alias de `q`)
}
 
// En este ejemplo, la conversión estilo C se interpreta como static_cast
// aunque funcionaría como reinterpret_cast
struct A {};
struct I1 : A {};
struct I2 : A {};
struct D : I1, I2 {};
 
int main()
{
    D* d = nullptr;
//  A* a = (A*)d;                   // error en tiempo de compilación
    A* a = reinterpret_cast<A*>(d); // esto compila
    assert(a == nullptr);
 
    cpp23_decay_copy_demo();
}

Salida:

x:2 y:2
x:2 y:1

[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
P2915R0 C++11 La adición del tipo de retorno al final introdujo más ambigüedades. Las resuelve.
CWG 2620 C++98 La resolución de parámetros de función ambiguos podría ser malinterpretada. Se mejoró la redacción.
CWG 2828 C++98 Una conversión estilo C estaba mal formada si existen múltiples interpretaciones
de un static_cast seguido de un const_cast,
independientemente de si estas conversiones se usan realmente.
Solo considera las
conversiones
posiblemente en uso.

[editar] Referencias

  • El estándar C++23 (ISO/IEC 14882:2023):
  • 7.6.1.4 Conversión de tipo explícita (notación funcional) [expr.type.conv]
  • 7.6.3 Conversión de tipo explícita (notación de conversión) [expr.cast]
  • El estándar C++20 (ISO/IEC 14882:2020):
  • 7.6.1.4 Conversión de tipo explícita (notación funcional) [expr.type.conv]
  • 7.6.3 Conversión de tipo explícita (notación de conversión) [expr.cast]
  • El estándar C++17 (ISO/IEC 14882:2017):
  • 8.2.3 Conversión de tipo explícita (notación funcional) [expr.type.conv]
  • 8.4 Conversión de tipo explícita (notación de conversión) [expr.cast]
  • El estándar C++14 (ISO/IEC 14882:2014):
  • 5.2.3 Conversión de tipo explícita (notación funcional) [expr.type.conv]
  • 5.4 Conversión de tipo explícita (notación de conversión) [expr.cast]
  • El estándar C++11 (ISO/IEC 14882:2011):
  • 5.2.3 Conversión de tipo explícita (notación funcional) [expr.type.conv]
  • 5.4 Conversión de tipo explícita (notación de conversión) [expr.cast]
  • El estándar C++03 (ISO/IEC 14882:2003):
  • 5.2.3 Conversión de tipo explícita (notación funcional) [expr.type.conv]
  • 5.4 Conversión de tipo explícita (notación de conversión) [expr.cast]
  • El estándar C++98 (ISO/IEC 14882:1998):
  • 5.2.3 Conversión de tipo explícita (notación funcional) [expr.type.conv]
  • 5.4 Conversión de tipo explícita (notación de conversión) [expr.cast]

[editar] Véase también

const_cast conversión
agrega o quita const
Original:
adds or removes const
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
[editar]
static_cast conversión
realiza conversiones básicas
Original:
performs basic conversions
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
[editar]
dynamic_cast conversión
realiza conversiones marcadas polimórficos
Original:
performs checked polymorphic conversions
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
[editar]
reinterpret_cast conversión
realiza en general de bajo nivel conversiones
Original:
performs general low-level conversions
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
[editar]
conversiones estándar
conversiones implícitas de un tipo a otro
Original:
implicit conversions from one type to another
The text has been machine-translated via Google Translate.
You can help to correct and verify the translation. Click here for instructions.
[editar]
Documentación de C para cast operator