2009-05-15 18 views
23

Varios comentarios sobre una respuesta reciente mía, What other useful casts can be used in C++, sugieren que mi comprensión de las conversiones en C++ es incorrecta. Solo para aclarar el problema, considere el siguiente código:C++ conversiones implícitas

#include <string> 

struct A { 
    A(const std::string & s) {} 
}; 

void func(const A & a) { 
} 

int main() { 
    func("one");     // error 
    func(A("two"));   // ok 
    func(std::string("three")); // ok 
} 

Mi afirmación es que la primera llamada a la función es un error, becauuse no hay conversión de un const char * a una A. Hay una conversión de una cadena a una A, pero usar esto involucraría más de una conversión. Mi entendimiento es que esto no está permitido, y esto parece ser confirmado por los compiladores de cometa g ++ 4.4.0 &. Con Comeau, me sale el siguiente error:

"ComeauTest.c", line 11: error: no suitable constructor exists 
     to convert from "const char [4]" to "A" 
     func("one");     // error 

Si se puede señalar, dónde estoy equivocado, ya sea aquí o en la respuesta original, preferentemente con referencia al estándar de C++, por favor hágalo.

Y la respuesta del estándar de C++ parece ser:

At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.

Gracias a Abhay para proporcionar la cita.

+0

Lamento que me haya equivocado en el comentario de su respuesta. Leí "La resolución de sobrecarga se usa para seleccionar la conversión definida por el usuario que se invocará", y me dije a mí mismo 'bueno, luego se resolverá en A (const de cadena &) y pasará' uno '', pero fallé por completo pensar en lo que dice 13.3.3.1.2: "Una secuencia de conversión definida por el usuario consiste en una secuencia de conversión estándar inicial seguida de una conversión definida por el usuario (12.3) seguida de una segunda secuencia de conversión estándar". Pero "uno" -> cadena no sería una secuencia de conversión estándar, sino que requeriría otra secuencia de conversión definida por el usuario. –

+0

siempre y cuando no pierda mis canicas :-) –

+0

¡Gran pregunta! La discusión implica que 'std :: string' no es parte del lenguaje y las conversiones a/desde él son" definidas por el usuario ". Al menos eso es lo que entiendo, corrígeme si me equivoco. Sería bueno si la pregunta fuera más explícita sobre esto. El estado exacto de 'std :: string' puede ser muy claro para las viejas manos de C++, pero no es tan fácil de realizar para las personas que llegaron al idioma en este siglo. –

Respuesta

12

Creo que la respuesta de sharptooth es precisa. La sección 12.3.4 del Estándar de C++ (SC22-N-4411.pdf) titulada 'Conversiones' deja en claro que solo se permite una conversión implícita definida por el usuario.

1 Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (Clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9).

2 User-defined conversions are applied only where they are unambiguous (10.2, 12.3.2). Conversions obey the access control rules (Clause 11). Access control is applied after ambiguity resolution (3.4).

3 [ Note: See 13.3 for a discussion of the use of conversions in function calls as well as examples below. —end note ]

4 At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.

+0

Me siento obligado a compartir por qué disfruto el uso de conversiones implícitas en un escenario específico: es decir, cuando quiero acoplar una variable de un tipo simple con una clase que realiza funciones relacionadas en la variable. Además de la conversión implícita, proporciono una función en la clase que devuelve el valor, de la misma manera que std :: string proporciona c_str(). Luego puede tener la funcionalidad de clase adicional donde sea necesario, y puede ser extremadamente liviano en cualquier otro lugar, a la vez que mantiene la funcionalidad relacionada entre sí. – moodboom

8

Es cierto, solo se permite la conversión implícita.

dos conversiones en una fila se pueden realizar con una combinación de un operador de conversión y un constructor parametrizado pero esto causa un C4927 warning - "conversión ilegal; más de una conversión definida por el usuario se ha aplicado implícitamente" - en VC++ para una razón.

5

The C++ Programming Language (4ª. Ed.) (sección 18.4.3) dice que

only one level of user-defined implicit conversion is legal

Esa parte lo hace sonar como múltiples conversiones implícitas "definido por el usuario" puede permitirse si algunos son entre nativa tipos.

+0

+1 para cotización de la última edición. del libro de Stroustrup – mloskot

9

A medida que el consenso parece ser ya: si tienes razón.

Pero como esta pregunta/respuesta probablemente se convertirá en el punto de referencia para las conversiones implícitas C++ en StackOverflow me gustaría añadir que para los argumentos de plantilla Las reglas son diferentes.

No se permiten conversiones implícitas para los argumentos que se utilizan para la deducción del argumento de la plantilla. Esto puede parecer bastante obvio, pero no obstante puede conducir a sutiles rarezas.

ejemplo de ello, std :: string operadores de suma

std::string s; 
s += 67; // (1) 
s = s + 67; // (2) 

(1) compila y funciona bien, operator+= es una función miembro, el parámetro de carácter plantilla ya se deduce creando instancias para std::string s (a char) Por lo tanto, se permiten las conversiones implícitas (int ->char), los resultados en s contienen el equivalente de caracteres 67, p. Ej.en ASCII esto se convertiría en 'C'

(2) da un error del compilador como operator+ se declara como una función gratuita y aquí el argumento de carácter plantilla se utiliza en la deducción.

Cuestiones relacionadas