2012-04-23 26 views
10

EDITAR: Siguiendo el comentario de Mike Seymour, reemplacé operator std::string() const; con operator char *() const; y modifiqué 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 con respecto al std::basic_string? No estoy seguro de haberlo entendido correctamente.Preferencia de operadores de conversión implícita C++


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 las siguientes:

  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)?
  2. ¿Hay alguna documentación que explique qué moldes implícitos están permitidos y cuál es su orden de precedencia? Parece que si añado un operador entero sin signo de esta clase en conjunto con el operador entero largo sin signo, recibo un error de compilación sobre la ambigüedad para el operador < < ...
  3. Además, sé que la definición de un operador de este tipo puede ser 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?
+0

Esto está relacionado con: [Error de resolución de sobrecarga al transmitir un objeto a través de la conversión implícita a una cadena] (http://stackoverflow.com/questions/6677072/overload-resolution-failure-when-streaming-object-via-implicit-conversion -to-str) –

+0

@Als: Vamos a tomarlo con calma ... No estoy preparado para bucear en las plantillas todavía :) –

Respuesta

8

Después se quita el operador unsigned int largo, ¿por qué necesito para emitir x std :: string explícitamente? ¿Por qué no llama directamente al operador de conversión implícita (std :: string)?

La versión de << para cuerdas es una plantilla, parametrizado por los parámetros de la plantilla std::basic_string (std::string sí mismo ser una especialización de la plantilla). Solo se puede elegir mediante búsqueda dependiente de argumentos, y eso solo funciona si el argumento es realmente una especialización de std::basic_string, no algo convertible a eso.

¿Existe 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 mediante búsqueda dependiente de argumentos.

No estoy seguro de entender completamente las advertencias asociadas. ¿Alguien podría describirlos?

No los entiendo completamente tampoco; 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. Usted puede arreglar su problema dejando ellos y utilizarlos de forma explícita cuando sea necesario:

std::cout << std::string(x) << std::endl; 

En C++ 11, se pueden declarar explicit, por lo que sólo se pueden utilizar 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 supuesto, el tipo de retorno de main() debe ser int, no void.

+0

Mike: Gracias por tomarse el tiempo para proporcionar un comentario tan detallado. Sí aclara las cosas un poco. Además, gracias por detectar ese pequeño problema con "void main". Debería recordar usar la versión correcta, no importa qué :) –

Cuestiones relacionadas