2010-02-10 13 views
9

Para probar y mostrar el resultado de algunas funciones de mi biblioteca, estoy creando un conjunto de funciones útiles.Sobrecarga del operador de conversión de tipo global

que tienen una función execute que se parece a:

template <typename R, typename I> 
std::string execute(const std::string& func_name, R(*func_ptr)(const I&), const I& func_input); 

Se llama a la función, y mostrar los resultados y argumentos en una cadena con formato que pueda enviar a std::cout.

El problema es que algunas de mis funciones no devuelven convertibles a cadena resultados. Pensé que simplemente podría sobrecargar el mundial ::operator std::string con algo como:

template <typename T> 
operator std::string(const std::vector<T>& v); 

Pero GCC se queja:

error: 'operator std::string(const std::vector<T, std::allocator<_CharT> >&)' must be a nonstatic member function 

Bueno, el problema, por supuesto, es que no puedo añadir operadores miembros de std::vector, e incluso para mis clases, no quiero contaminarlas con "para probar" operadores de conversión.

Supongo que puedo agregar una capa de direccionamiento indirecto y utilizar una función en lugar de un operador de conversión, pero esa no sería la solución más estética. También podría sobrecargar ::operator << para std::ostream y usar un std::ostringstream, pero esa tampoco es la solución más limpia.

Me pregunto si el operador de conversión global realmente no se puede descargar, y si es así, por qué.

Respuesta

10

Los operadores de conversión (operadores de conversión) deben ser un miembro de la clase convertible que produce el tipo convertido. Como operadores de asignación, deben ser funciones miembro, como su compilador le está diciendo.

Dependiendo de la cantidad de esfuerzo que desee poner en la parte de depuración, podría intentar usar la metaprogramación para reenviar su método de ejecución a diferentes implementaciones reales, proporcionando las específicas para los contenedores que imprimirán los contenidos.

¿Por qué no quiere proporcionar operator<< para sus tipos? Creo que esa es realmente la solución idiomática.A diferencia de otros lenguajes que usa métodos que convierten en cadena para producir resultados imprimibles, en C++ la forma idiomática es proporcionar operator<< y luego usar stringstreams (o boost::lexical_cast o alguna solución similar) para convertir a cadenas basadas en la implementación operator<<. Existe una clase de utilidad simple here para crear un string a partir de elementos que anulan operator<< si desea usar eso para un punto de inicio.

1

No hay un operador de conversión global definido por el usuario. Debe controlar el tipo de destino (en cuyo caso un constructor de parámetro no explícito es el operador de conversión) o el tipo de fuente (en cuyo caso debe sobrecargar el objetivo del operador miembro()).

4

Me pregunto si el operador de conversión global realmente no se puede descargar, y si es así, por qué.

No, no existe tal cosa. Las funciones de conversión deben ser miembros de una clase. Si no fuera así, la resolución de sobrecarga sería un problema particularmente molesto para el compilador al introducir ambigüedades.

+1

Sin embargo, muchos operadores están disponibles como miembro de global o, por qué no ésta? Por ejemplo, si hay un operador global y miembro <<, el compilador se queja por una llamada ambigua, podría hacer lo mismo con las conversiones. – NewbiZ

+2

Las funciones de conversión son funciones especiales de los miembros (como son ctor, dtor, op = y copy-constructor) ya que participan en la creación de conversiones/objetos. Ver 12.3. – dirkgently

0

Una función de conversión debe ser una función miembro. La función puede no especificar un tipo de devolución, y la lista de parámetros debe estar vacía. Deben usarse con moderación y debe haber una ruta de conversión clara de un tipo a otro. De lo contrario, pueden dar lugar a resultados inesperados y errores misteriosos.

0

Lamentablemente, no existe un operador de colada global. Asombrosamente. Pero las plantillas son tu amigo.

A veces no desea exponer el casting a la interfaz puesto que querría mantener este anónimo solo para una implementación específica. Normalmente agrego una plantilla como método() a la clase que también puede hacer comprobaciones de tipo en el molde, etc. y le permite manejar la forma en que desea implementar el casting (por ejemplo, dinámico, compartido, ref, etc.).

Algo como esto:

template< class EvtT >const EvtT& as() const throw(std::exception) 
    { 
     const EvtT* userData = static_cast<const EvtT*>(m_UserData); 
     ASSERT(userData, "Fatal error! No platform specific user data in input event!"); 
     return *userData; 
    } 

m_UserData es un tipo anónimo que sólo conoce la implementación. Si bien este es estrictamente un elenco no tipado (no utilizo cecas de tipo aquí), esto podría ser reemplazado por un dynamic_cast y excepciones de casting adecuadas.

La aplicación simplemente hace esto:

unsigned char GetRawKey(const InputEvent& ie) 
    { 
     const UserEvent& ue = ie.as<const UserEvent>(); 
     ...