2010-09-12 13 views
12

funciona este código:función vs declaración de variables en C++

std::ifstream f(mapFilename.c_str()); 
std::string s = std::string(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>()); 
ParseGameState(s); 

medio de las cuales es una mapFilenamestd::string y void ParseGameState(const std::string&);.

Y esto no es así:

std::ifstream f(mapFilename.c_str()); 
std::string s(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>()); 
ParseGameState(s); 

Este es el error:

game.cpp: In member function ‘int Game::LoadMapFromFile(const std::string&)’: 
game.cpp:423: error: no matching function for call to ‘ParseGameState(std::string (&)(std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> > (*)()))’ 
game.cpp:363: note: candidates are: ParseGameState(const std::string&) 

por lo que parece que reconoce s como una declaración de la función y no una declaración de variables en este caso.

¿Por qué es eso? ¿Es esto un error en GCC 4.2.1 (compilación de Apple)? ¿O GCC maneja esto correctamente? ¿Está esto indefinido en el estándar de C++?

Respuesta

14

Este es el "análisis más irritante" de C++. Un Google rápido para eso debería aparecer un montón de éxitos con muchos detalles. La respuesta básica es que sí, el compilador es tratándolo como una declaración de función, y C++ requiere que lo haga. No hay nada malo con su compilador (al menos a este respecto).

Si tiene alguna comodidad, tiene mucha buena compañía para toparse con esto. De hecho, es suficientemente común que a C++ 0x se le agregue una nueva sintaxis de inicialización de llaves, en gran parte porque evita esta ambigüedad. Al usarlo, usted podría escribir algo como:

std::string s{std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>()}; 

que hará más claro que el contenido de los apoyos están destinados a ser valores para inicializar s, no tipos de parámetros a una función llamada s. No sé si Apple todavía tiene un puerto, pero gcc acepta la nueva sintaxis a partir de la versión 4.5 (más o menos).

Editar: Al volver a leer N3092, Johannes es (como siempre) bastante correcto. El lenguaje aplicable es (§8.5.4/3/5): "Si T tiene un constructor de lista de inicialización, la lista de argumentos consta de la lista de inicializadores como un único argumento, de lo contrario, la lista de argumentos consta de los elementos del inicializador lista."

lo tanto, ya std::string tiene una inicialización del constructor de vinos, esta intentaría "cosas" las dos istreambuf_iterator s en una lista de inicialización, y pasar a la que Héctor std::string que toma una lista de inicialización - pero eso sería una escriba no coincidencia, por lo que el código no se puede compilar. Para otro tipo de tipo que (a diferencia de std::string hizo no tiene un ctor de lista de inicialización) la transformación anterior funcionaría (gracias a "de lo contrario ..." en la cita anterior). En el caso de std::string, tendría que usar una de las alternativas actuales, como std::string s = std:string(...).

Pido disculpas por la solución incorrecta sugerida, en este caso, una que es aún peor porque confunde un problema que probablemente será excesivamente confuso por sí solo, y si algo necesita una aclaración cuidadosa, especialmente en los próximos años.

+1

Gracias! [Aquí en WP] (http://en.wikipedia.org/wiki/Most_vexing_parse) también es una buena explicación sobre el análisis más irritante. – Albert

+1

Parece que la declaración de la variable 'std :: string' anterior no funcionará en C++ 0x: Debido a que' std :: string' tiene un constructor de listas de inicialización, todo el '{...} 'se tomará como un único argumento, e intentará inicializar el parámetro' initializer_list 'y no se compilará :( –

+1

@Johannes: Sí, creo que tienes razón. Casi me pregunto si no sería mejor si esto fue reformulado entonces, en lugar de considerar un inicializador de lista y luego (solo si no estaba presente) considerar otros ctors, sino crear un conjunto de sobrecarga y seleccionar la mejor coincidencia, probablemente con el ajuste menor que al crear un initializer_list sería equivalente a ninguna conversión con respecto a la bondad de coincidencia (con la condición de que solo he pensado en ello unos minutos, por lo que podría causar un problema sutil (o incluso evidente) que me falta). –

Cuestiones relacionadas