sobrecarga - Precedencia de Operadores de Conversión Implícita de C++
sobrecarga de operadores c++ pdf (1)
Después de eliminar el operador unsigned long int, ¿por qué necesito convertir x a std :: string explícitamente? ¿Por qué no llama directamente al operador de conversión implícita (std :: string)?
La versión de <<
para cadenas es una plantilla, parametrizada por los parámetros de la plantilla std::basic_string
( std::string
sí es una especialización de esa plantilla). Solo se puede elegir mediante búsquedas dependientes de argumentos, y eso solo funciona si el argumento es realmente una especialización de std::basic_string
, no algo convertible a eso.
¿Hay alguna documentación que explique qué moldes implícitos están permitidos y cuál es su orden de precedencia?
Las reglas son bastante complejas, y necesitarás leer el estándar de C ++ para la historia completa. Las simples reglas empíricas son que las conversiones implícitas no pueden contener más de una conversión definida por el usuario y (como ha descubierto) el resultado de una conversión implícita no se puede utilizar para elegir una especialización de plantilla por búsqueda dependiente de argumentos.
No estoy seguro de entender completamente las advertencias asociadas. ¿Alguien podría describirlos?
Yo tampoco los entiendo del todo; las interacciones entre las conversiones implícitas, la búsqueda de nombres y la especialización de plantillas (y probablemente otros factores en los que no puedo pensar ahora) son bastante complejas, y la mayoría de las personas no tiene la inclinación de aprenderlas todas. Hay bastantes casos en los que la conversión implícita no sucederá, y otros en los que podría suceder cuando no lo esperas; Personalmente, me resulta más fácil simplemente evitar conversiones implícitas la mayor parte del tiempo.
¿Sería mejor práctica simplemente definir los métodos públicos ToUnsignedLongInt y ToString?
Probablemente sea una buena idea, para evitar conversiones no deseadas. Puede solucionar su problema dejándolo y utilícelos explícitamente cuando sea necesario:
std::cout << std::string(x) << std::endl;
En C ++ 11, puede declararlos explicit
, de modo que solo se puedan usar de esta manera. En mi opinión, esa sería la mejor opción si puedes; de lo contrario, usaría funciones de conversión explícitas como sugiera.
Por cierto, el tipo de retorno de main()
debe ser int
, no void
.
EDITAR: Siguiendo el comentario de Mike Seymour, reemplacé el operator std::string () const;
con operator char * () const;
y cambió la implementación en consecuencia. Esto permite la conversión implícita, pero, por alguna razón, el operador largo sin signo tiene precedencia sobre el operador char *, lo que simplemente no se siente bien ... Además, no quiero exponer cosas C desagradables como char * fuera del clase, cuando tengo std :: string. Tengo la corazonada de que mi clase CustomizedInt necesita heredar de algunas cosas para poder soportar la función que deseo. ¿Podría alguien elaborar el comentario de Mike sobre std::basic_string
? No estoy seguro de haberlo entendido correctamente.
Tengo este pedazo de código:
#include <string>
#include <sstream>
#include <iostream>
class CustomizedInt
{
private:
int data;
public:
CustomizedInt() : data(123)
{
}
operator unsigned long int () const;
operator std::string () const;
};
CustomizedInt::operator unsigned long int () const
{
std::cout << "Called operator unsigned long int; ";
unsigned long int output;
output = (unsigned long int)data;
return output;
}
CustomizedInt::operator std::string () const
{
std::cout << "Called operator std::string; ";
std::stringstream ss;
ss << this->data;
return ss.str();
}
int main()
{
CustomizedInt x;
std::cout << x << std::endl;
return 0;
}
Que imprime "Operador llamado unsigned long int; 123". Mis preguntas son estas:
- Después de eliminar el operador unsigned long int, ¿por qué necesito convertir x a std :: string explícitamente? ¿Por qué no llama directamente al operador de conversión implícita (std :: string)?
- ¿Hay alguna documentación que explique qué moldes implícitos están permitidos y cuál es su orden de precedencia? Parece que si agrego un operador unsigned int a esta clase junto con el operador unsigned long int, recibo un error de compilación sobre la ambigüedad para el operador << ...
- Además, sé que la definición de dicho operador puede ser una mala práctica, pero no estoy seguro de entender completamente las advertencias asociadas. ¿Alguien podría describirlos? ¿Sería mejor práctica simplemente definir los métodos públicos ToUnsignedLongInt y ToString?