2009-05-29 18 views
16

Soy un principiante en C++, lo siento si la pregunta es demasiado básica.Creador de cadenas C++ vacío

He intentado recoger los constrcturs de cadena y probarlos todos (para recordarlos).

string strA();   // string(); empty string // incorrect 
string strB("Hello"); // string(const char* str) 
string strC("Hello",3); // string(const char* str, size_type length) 
string strD(2,'c');  // string(size_type lenght, const char &c) 
string strE(strB);  // string(const string& s) 

cout << strA << endl; 
cout << strB << endl; 
cout << strC << endl; 
cout << strD << endl; 
cout << strE << endl; 

Todos ellos trabaja a excepción de la strA. Imprime "1". ¿Por qué? ¿Cuál es el tipo de strA en este caso? ¿Cómo puedo verificar el tipo de cosas cuando no estoy seguro?

me he dado cuenta de que la forma correcta es la siguiente (que por cierto parece ser incompatible con las demás constructores, a veces parens veces no hay parens):

string strA; 

ps: pregunta en irrelevantes negrita, habitual las respuestas serán downvoted.

Respuesta

32

Este es un gotcha muy popular. La gramática de C++ es ambigua. Una de las reglas para resolver ambigüedades es "si algo parece una declaración, es una declaración". En este caso, en lugar de definir una variable, declaraste un prototipo de función.

string strA(); 

es equivalente a

string strA(void); 

un prototipo de una función sin argumentos que devuelve cadena.

Si desea llamar explícitamente constructor sin argumentos intente esto:

string strA=string(); 

No es totalmente equivalente - que significa 'crear una cadena temporal usando el constructor sin argumentos y luego copiarlo para inicializar variables strA ', pero el compilador puede optimizarlo y omitir la copia.

EDIT: Here is an appropriate item in C++ FAQ Lite

+3

Y esta es una de las razones por las que dejé de usar C++. –

+3

@Dietrich Epp: Esto también me molestó. Supongo que este es el precio pagado para mantener la compatibilidad con C. La alternativa es usar C, que tiene su tonelada métrica de problemas, creo que es mejor mantener C++ y evitar esa trampa. – paercebal

+0

¿qué tal 'std :: string strA (" ");' – CaptainDaVinci

13

Se considera

string strA(); 

como una declaración de la función.

Para uso constructor por defecto:

string strA; 
+2

Puede usar esa notación al asignar el montón: cadena * strA = cadena nueva(); – Skilldrick

6

En C++, como en C, hay una regla que dice que cualquier cosa que se parece a un declarartion será tratada como una declaración.

string strA(); 

parece una declaración de función, por lo que se trata como una sola. Es necesario:

string strA; 
1

compilador interpreta string strA() como un prototipo de función de una función que toma argumentos vacíos y devuelve un objeto de tipo cadena. Si desea crear un objeto de cadena vacío use string strA; (sin paranthesis)

3

Imprime 1 porque los punteros a funciones se convierten siempre a numérico como true.

+5

Solo si el puntero a la función no es nulo. De todos modos, un puntero a la función debe apuntar a su definición, y eso falta aquí. Esto no debería haber vinculado. – MSalters

2

tkopec tiene razón sobre por qué no funciona. Para responder a su segunda pregunta, he aquí cómo se comprueba el tipo:

template<typename TEST> void Error_() { 
    TEST* MakeError = 1; 
} 

Llamando Error_(StrA); obtendrá un error de compilación, y su compilador probablemente le dirá que sucedió en Error_< std::basic_string<char, std::allocator<char> > (*)(void)>(std::basic_string<char, std::allocator<char> > (*)(void)) Ahora, std :: basic_string> es solo std :: string, entonces esto realmente significa Error_< std::string (*)(void)> (std::string (*)(void)). La parte entre '<>' se repite entre '()', y ese es el tipo de strA. En este caso, std::string (*)(void).

+0

Tipo de strA es una función. std :: string (void). No es un puntero de función. Tendría que declararlo como una cadena (* strA)(); si él quisiera que fuera un puntero a la función.Probablemente sé lo que querías decir, pero tus últimas frases suenan como si dijeras que es un puntero a la función. –

4

No creo que en este caso, se aplique la regla "si pudiera ser una declaración, se toma como una declaración". Dado que en la siguiente, ambos cosas son declaraciones

string a; 
string a(); 

El uno es la declaración de un objeto, y el otro es la declaración de una función. La regla se aplica en otros casos. Por ejemplo, en este caso:

string a(string()); 

En ese caso, string() puede significar dos cosas.

  • Declaración de un parámetro de función sin nombre
  • Expresión creación de un defecto construido string

El fule se aplica aquí, y string() se toma para significar lo mismo que la siguiente, los parámetros con nombre (nombres son irrelevantes en parámetros cuando se declara una función)

string a(string im_not_relevant()); 

Si una función toma como parámetro una matriz o una anotación su función, ese parámetro decae en un puntero. En el caso de un parámetro de función, a un puntero a la función. Por lo tanto, es equivalente a la siguiente, que puede parecer más familiar

string a(string (*im_not_relevant)()); 

Pero en tu caso, es más bien la sintaxis que está metiendo en el camino. Está diciendo que la siguiente es una declaración de función. Nunca puede ser la declaración de un objeto (a pesar de que fue pensado probablemente por el programador!)

string a(); 

lo que no hay ambigüedad en este contexto, en primer lugar, y por lo tanto se declara una función. Como string tiene un constructor definido por el usuario, puede omitir los paréntesis y el efecto sigue siendo el mismo que el previsto.