programas - ¿Por qué es esta una declaración hacia adelante en C++?
tipos de datos en c++ (2)
El estándar C ++ también define esta
struct tm
como un tipo de parámetro de función como declaración directa. Por favor, ayuda para explicar esto y la cuota de la norma será útil.
Sí, struct tm timeval
introducirá un nuevo nombre de clase xm::tm
aquí.
(explicaciones y citas)
struct tm
es un especificador de tipo elaborado , que podría usarse para introducir un nuevo nombre de clase.
$ 3.1 / 4 Declaraciones y definiciones [basic.def]
[Nota: Un nombre de clase también puede ser declarado implícitamente por un especificador de tipo elaborado ([dcl.type.elab]). - nota final]
$ 9.1 / 2 nombres de clase [class.name] :
Una declaración que consiste únicamente en el identificador de clave de clase; es una redeclaración del nombre en el alcance actual o una declaración de reenvío del identificador como nombre de clase. Introduce el nombre de la clase en el ámbito actual.
$ 3.4.4 / 2 Especificadores de tipo elaborados [basic.lookup.elab] :
o si el especificador de tipo elaborado aparece en una declaración con el formulario:
class-key attribute-specifier-seqopt identifier ;
El especificador de tipo elaborado es una declaración que introduce el nombre de clase como se describe en [basic.scope.pdecl].
$ 3.3.2 / 7 Punto de declaración [basic.scope.pdecl] :
si el especificador de tipo elaborado se utiliza en el decl-specifier-seq o en la cláusula de declaración de parámetro de una función definida en el ámbito del espacio de nombres, el identificador se declara como un nombre de clase en el espacio de nombres que contiene la declaración;
Para struct tm timeval
utilizado como declaración de parámetros de función, ya que <time.h>
no está incluido y todavía no existe una clase llamada tm
, la clase tm
se declarará en el alcance actual (es decir, el espacio de nombres xm
), luego se declarará xm::tm
.
Tendré el siguiente fragmento de código en utilA.cpp:
// utilB.h
namespace xm
{
void zoo(struct tm timeval); //<-----line 0
}
// utilA.cpp
#include <utilB.h> //<----line 1
#include <time.h> //<----line 2
namespace xm
{
void foo()
{
struct tm time1 = {0}; //<----line 3
}
}
GCC se queja cuando compila utilA.cpp,
error: variable ''xm::tm time1'' has initializer but incomplete type
Parece que esto se debe a que utilA.h
está usando struct tm
en la línea 0, pero sin incluir el time.h
, y el compilador trata a la struct tm
en la línea 0 como una declaración hacia adelante, por lo que la struct tm
en la línea 2 se resuelve como xm::tm
dentro del encabezado en la línea 0.
Entonces, ¿el estándar de C ++ define esta struct tm
como un tipo de parámetro de función como declaración directa? Por favor ayude a explicar esto y las citas de la norma serán útiles.
En la línea 0, declaró una clase llamada tm
dentro del espacio de nombres xm
. Sí, C ++ permite declarar tipos en parámetros de función / plantilla.
N4140 § 3.4.4 [basic.lookup.elab] / 2
Si la clave de clase introduce el especificador de tipo elaborado y esta búsqueda no encuentra un nombre de tipo declarado previamente, o si el especificador de tipo elaborado aparece en una declaración con el formulario:
class-key atributo-especificador-seq identificador opt ;
El especificador de tipo elaborado es una declaración que introduce el nombre de clase como se describe en 3.3.2.
Debido a que declaró una clase llamada tm
dentro del espacio de nombres xm
, es el primer nombre que la búsqueda de nombres encuentra para tm
en la línea 3. ::tm
(y ::std::tm
) no se consideran. Y como no hay una definición de class ::xm::tm
, el compilador se queja de que es un tipo incompleto.
Si no estuvieras escribiendo el código C en C ++, escribirías algo como 1
struct tm;
namespace xz{
void zoo(tm timeval);
}
o
#include <ctime>
namespace xz{
void zoo(tm timeval);
}
y no tendrías ese problema.
1 recuerda que no puedes reenviar nombres en el espacio de nombres estándar