2008-11-25 8 views
11

Al haber introducido recientemente una sobrecarga de un método, la aplicación comenzó a fallar. Finalmente rastreando, se llama al nuevo método donde no esperaba que fuera.¿Por qué el compilador elige bool sobre string para typecast implícito de L ""?

Tuvimos

setValue(const std::wstring& name, const std::wstring& value); 

std::wstring avalue(func()); 
setValue(L"string", avalue); 
std::wstring bvalue(func2() ? L"true", L"false"); 
setValue(L"bool", bvalue); 
setValue(L"empty", L""); 

fue cambiado de modo que cuando se almacena un valor bool que utilizamos las mismas cadenas (almacenamiento de datos interna de cuerdas)

setValue(const std::wstring& name, const std::wstring& value); 
setValue(const std::wstring& name, const bool& value); 

std::wstring avalue(func()); 
setValue(L"string", avalue); 
setValue(L"bool", func2()); 
setValue(L"empty", L""); << --- this FAILS!?! 

El problema con L "" es que está lanzando implícitamente y anteriormente estaba contento de ser un std :: wstring, pero no prefiere ser un bool. El compilador de MSVC no se queja o genera una advertencia, por lo que me preocupa que incluso si "soluciono" el setValue (L "vacío", L ""); ser

setValue(L"empty", std::wstring()); 

otra persona puede venir más tarde y sólo tiene que utilizar setValue (L "vacío", L ""); y tenemos que seguir este problema de nuevo.

Pensamos utilizar explícito en el método, pero no es una palabra clave válida para este uso. ¿Hay alguna forma de que el compilador se queje de esto o evite el problema? De lo contrario, estoy pensando en cambiar el nombre del método que toma un bool para asegurarse de que no puede hacer una suposición incorrecta.

+0

Agregado a mi lista de razones por las cuales C++ no es el mejor idioma. – Qix

Respuesta

10

En primer lugar, la causa de este problema: el estándar 13.3.3.2 de C++ define un orden para las secuencias de conversión. Dice que una secuencia de conversión definida por el usuario es peor que una secuencia de conversión estándar. Lo que sucede en su caso es que el literal de cadena se somete a una conversión booleana (definida en 4.12. Esta es una conversión estándar). No utiliza la conversión definida por el usuario a std::wstring que sería necesaria si tomara la otra sobrecarga.

Recomendaría simplemente cambiar el nombre de una de las sobrecargas o agregar una sobrecarga que acepte el literal de cadena directamente (usando el tipo de parámetro wchar_t const*).

+0

Gracias por el enlace al estándar y el contenedor para bool también fue una sugerencia útil. –

+0

Cite el texto estándar incorrecto en aquel momento y pensé que mi respuesta era innecesariamente compleja. Agregar un oveload para 'wchar_t const *' es mejor, creo. Siéntase libre de dar la marca de verificación a Mark-Ransom ahora, que básicamente dice lo mismo. –

0

Puede hacer que la nueva función tome otro tipo de bool, tal vez solo un proxy para bool, que no es convertible desde una cadena literal. Pero realmente cambiaría el nombre de la función de toma de booleos y terminaría con eso.

1

Para simplificar un poco, el siguiente código

#include <iostream> 
using namespace std; 

void f(const string &s) 
{ cout << "string version called" << endl; } 

void f(const bool &b) 
{ cout << "bool version called" << endl; } 

int main() 
{ f("Hello World"); } 

imprime "bool versión llamada". ¿Estás seguro de que tu código falla solo con la cadena vacía?

+0

Actualmente, no usamos un literal de cadena a excepción de la cadena vacía. Creo que tiene toda la razón de que no tiene nada que ver con que la cadena esté vacía. –

+0

El literal de la cadena no necesita estar vacío, el compilador siempre preferirá que el molde pase a la inicialización de la clase de cadena. Por cierto, creo que vi advertencias en VC++ 2005 relacionadas con "forzar valor a bool". – MP24

8

L "" es un puntero a una cadena de caracteres anchos. El compilador cree que la conversión a bool tiene prioridad sobre una conversión a std :: wstring.

Para solucionar el problema, introducir una nueva setValue:

void setValue(std::wstring const& name, const wchar_t * value); 
+2

No exactamente. L "" es un literal de cadena de caracteres anchos. – ChrisN

2

Puesto que se un tipo incorporado, se prefiere la conversión de wchar_t a bool bool. Yo diría que la solución más simple es agregar una sobrecarga que tome una matriz wchar_t y emitir explícitamente allí:

setValue(const std::wstring& name, const wchar_t s[]) 
{ 
    setValue(name, wstring(s)); 
} 
Cuestiones relacionadas