studio reales proyectos programacion libro introducción incluye herramientas fundamentos fuente español código con avanzado aplicaciones c++ compiler-construction casting

c++ - reales - ¿Alguna forma de lanzar con el operador de clase solamente?



libro de android studio en español pdf (4)

Una especie de pregunta al azar ...

Lo que estoy buscando es una forma de expresar una operación de conversión que utiliza un operador definido de la instancia de clase desde la que estoy emitiendo, y genera un error en tiempo de compilación si no hay un operador de conversión definido para el tipo. Entonces, por ejemplo, lo que estoy buscando es algo así como:

template< typename RESULT_TYPE, typename INPUT_TYPE > RESULT_TYPE operator_cast( const INPUT_TYPE& tValue ) { return tValue.operator RESULT_TYPE(); } // Should work... CString sString; LPCTSTR pcszString = operator_cast< LPCTSTR >( sString ); // Should fail... int iValue = 42; DWORD dwValue = operator_cast< DWORD >( iValue );

Nota al margen interesante: el código anterior bloquea el compilador C ++ de VS2005 y no se compila correctamente en el compilador VS ++ de C ++ debido a que supongo que es un error del compilador, pero se espera que demuestre la idea.

¿Alguien sabe de alguna manera para lograr este efecto?

Editar: más racional, para explicar por qué podría usar esto. Supongamos que tiene una clase contenedora que se supone que debe encapsular o abstraer un tipo, y lo está convirtiendo al tipo encapsulado. Podrías usar static_cast <>, pero eso podría funcionar cuando quisieras que fallara (es decir: el compilador elige un operador que puede convertir al tipo que pediste, cuando querías una falla porque ese operador no estaba presente).

Es cierto que es un caso poco común, pero es molesto que no pueda expresar exactamente lo que quiero que el compilador haga en una función encapsulada ... de ahí la pregunta aquí.


Como los mensajes de error del compilador relacionados con la plantilla suelen ser un verdadero dolor de cabeza, si no le importa especificar cada conversión, puede hacer que el compilador emita un mensaje más instructivo en el caso de error al proporcionar también una definición de plantilla predeterminada. Esto utiliza el hecho de que el compilador solo intentará compilar el código en las plantillas que realmente se invocan.

#include <string> // Class to trigger compiler warning class NO_OPERATOR_CONVERSION_AVAILABLE { private: NO_OPERATOR_CONVERSION_AVAILABLE(){}; }; // Default template definition to cause compiler error template<typename T1, typename T2> T1 operator_cast(const T2&) { NO_OPERATOR_CONVERSION_AVAILABLE a; return T1(); } // Template specialisation template<> std::string operator_cast(const std::string &x) { return x; }


Parece que quieres especialización de plantillas, algo como esto sería:

/* general template */ template<typename T1, typename T2> T1 operator_cast(const T2 &x); /* do this for each valid cast */ template<> LPCTSTR operator_cast(const CString &x) { return (LPCTSTR)x; }

EDITAR: Como se indicó en otra publicación, puede poner algo en la versión general para darle un mensaje de error más útil si se realiza un lanzamiento no compatible.


El código que ha publicado funciona con el compilador Cameau (que generalmente es una buena indicación de que es válido en C ++).

Como sabes, un elenco válido consiste en no más de un elenco definido por el usuario, por lo que una solución posible en la que estaba pensando era agregar otro elenco definido por el usuario definiendo un nuevo tipo en la plantilla de elenco y tener una afirmación estática de que no estuviera disponible el reparto el nuevo tipo para el tipo de resultado (using boost is_convertible ), sin embargo, esto no distingue entre los operadores de elenco y los constructores de elenco (ctor con un argumento) y permite que se produzcan conversiones adicionales (por ejemplo, void* to bool ). No estoy seguro de si hacer una distinción entre los operadores de elenco y los constructores de elenco es lo correcto , pero eso es lo que dice la pregunta.

Después de un par de días reflexionando sobre esto, me golpeó, simplemente puede tomar la dirección del operador de reparto. Esto es un poco más fácil decirlo que hacerlo debido al puntero velludo de C ++ a la sintaxis de los miembros (me tomó mucho más de lo esperado para hacerlo bien). No sé si esto funciona en VS2008, solo lo comprobé en Cameau.

template< typename Res, typename T> Res operator_cast( const T& t ) { typedef Res (T::*cast_op_t)() const; cast_op_t cast_op = &T::operator Res; return (t.*cast_op)(); }

Editar: tuve la oportunidad de probarlo en VS2005 y VS2008. Mis hallazgos difieren de los del póster original.

  • En VS2008, la versión original parece funcionar bien (al igual que la mía).
  • En VS2005, la versión original solo bloquea el compilador cuando se lanza desde un tipo incorporado (por ejemplo, casting int a int) después de proporcionar un error de compilación que tampoco parece tan malo y mi versión parece funcionar en todos los casos.

Usar un constructor de conversión marcado como explícito es cómo evitaría que el compilador permita que los tipos convertidos implícitamente inicialicen su clase contenedora.