User-defined conversion function
Permite la conversión implícita o conversión explícita desde un class type a otro tipo.
Contenidos |
Sintaxis
La función de conversión se declara como una función miembro no estática o una plantilla de función miembro sin parámetros, sin tipo de retorno explícito, y con el nombre de la forma:
operator
conversion-type-id
|
(1) | ||||||||
explicit
operator
conversion-type-id
|
(2) | (desde C++11) | |||||||
explicit (
expression
)
operator
conversion-type-id
|
(3) | (desde C++20) | |||||||
conversion-type-id
es un
type-id
excepto que los operadores de función y array
[]
o
()
no están permitidos en su declarador (por lo tanto, la conversión a tipos como puntero a array requiere un alias de tipo/typedef o una plantilla de identidad: véase más abajo). Independientemente de typedef,
conversion-type-id
no puede representar un tipo array o un tipo función.
Aunque el tipo de retorno no está permitido en la declaración de una función de conversión definida por el usuario, la
decl-specifier-seq
de
la gramática de declaración
puede estar presente y puede incluir cualquier especificador excepto
type-specifier
o la palabra clave
static
. En particular, además de
explicit
, los especificadores
inline
,
virtual
,
constexpr
(desde C++11)
,
consteval
(desde C++20)
, y
friend
también están permitidos (nótese que
friend
requiere un nombre calificado:
friend
A
::
operator
B
(
)
;
).
Cuando dicha función miembro se declara en la clase X, realiza la conversión de X a conversion-type-id :
struct X { // conversión implícita operator int() const { return 7; } // conversión explícita explicit operator int*() const { return nullptr; } // Error: operador de array no permitido en conversion-type-id // operator int(*)[3]() const { return nullptr; } using arr_t = int[3]; operator arr_t*() const { return nullptr; } // OK si se hace mediante typedef // operator arr_t () const; // Error: conversión a array no permitida en ningún caso }; int main() { X x; int n = static_cast<int>(x); // OK: establece n a 7 int m = x; // OK: establece m a 7 int* p = static_cast<int*>(x); // OK: establece p a null // int* q = x; // Error: no hay conversión implícita int (*pa)[3] = x; // OK }
Explicación
La función de conversión definida por el usuario se invoca en la segunda etapa de la conversión implícita , que consiste en cero o un constructor de conversión o cero o una función de conversión definida por el usuario.
Si tanto las funciones de conversión como los constructores de conversión pueden utilizarse para realizar alguna conversión definida por el usuario, tanto las funciones de conversión como los constructores son considerados por la resolución de sobrecarga en contextos de inicialización por copia y inicialización por referencia , pero solo los constructores son considerados en contextos de inicialización directa .
struct To { To() = default; To(const struct From&) {} // constructor de conversión }; struct From { operator To() const {return To();} // función de conversión }; int main() { From f; To t1(f); // inicialización directa: llama al constructor // Nota: si el constructor de conversión no está disponible, se seleccionará el constructor de copia implícito // y se llamará a la función de conversión para preparar su argumento // To t2 = f; // inicialización por copia: ambigua // Nota: si la función de conversión es de un tipo no constante, ej. // From::operator To();, será seleccionada en lugar del constructor en este caso To t3 = static_cast<To>(f); // inicialización directa: llama al constructor const To& r = f; // inicialización de referencia: ambigua }
La función de conversión a su propia clase (posiblemente calificada cv) (o a una referencia de ella), a la base de su propia clase (o a una referencia de ella), y al tipo void puede definirse, pero no puede ejecutarse como parte de la secuencia de conversión, excepto, en algunos casos, mediante virtual dispatch:
struct D; struct B { virtual operator D() = 0; }; struct D : B { operator D() override { return D(); } }; int main() { D obj; D obj2 = obj; // no llama a D::operator D() B& br = obj; D obj3 = br; // llama a D::operator D() mediante despacho virtual }
También se puede llamar usando la sintaxis de llamada a función miembro:
struct B {}; struct X : B { operator B&() { return *this; }; }; int main() { X x; B& b1 = x; // no llama a X::operatorB&() B& b2 = static_cast<B&>(x); // no llama a X::operatorB& B& b3 = x.operator B&(); // llama a X::operatorB& }
Al realizar una llamada explícita a la función de conversión, conversion-type-id es ambicioso: es la secuencia más larga de tokens que podría formar un conversion-type-id (incluyendo atributos, si los hay) (desde C++11) :
& x.operator int * a; // error: interpretado como & (x.operator int*) a, // no como & (x.operator int) * a operator int [[noreturn]] (); // error: atributo noreturn aplicado a un tipo
|
El marcador de posición auto puede utilizarse en conversion-type-id , indicando un tipo de retorno deducido : struct X { operator int(); // OK operator auto() -> short; // error: trailing return type not part of syntax operator auto() const { return 10; } // OK: deduced return type operator decltype(auto)() const { return 10l; } // OK: deduced return type }; Nota: una plantilla de función de conversión no puede tener un tipo de retorno deducido. |
(desde C++14) |
Las funciones de conversión pueden heredarse y pueden ser virtual , pero no pueden ser static . Una función de conversión en la clase derivada no oculta una función de conversión en la clase base a menos que conviertan al mismo tipo.
La función de conversión puede ser una función miembro plantilla, por ejemplo,
std::auto_ptr<T>::operator auto_ptr<Y>
. Consulte
plantilla miembro
y
deducción de argumentos de plantilla
para las reglas especiales aplicables.
Palabras clave
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| CWG 296 | C++98 | las funciones de conversión podían ser estáticas | no pueden declararse estáticas |
| CWG 2016 | C++98 |
las funciones de conversión no podían especificar tipos de retorno,
pero los tipos están presentes en conversion-type-id |
los tipos de retorno no pueden especificarse en los
especificadores de declaración de funciones de conversión |
| CWG 2175 | C++11 |
no estaba claro si el
[
[
noreturn
]
]
en
operator int [ [ noreturn ] ] ( ) ; se analiza como parte de noptr-declarator (del declarador de función) o de conversion-type-id |
se analiza como parte de
conversion-type-id |