为什么这是 C++ 中的前向声明?
Why is this a forward declaration in C++?
我将在 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 在编译时报错 utilA.cpp,
error: variable 'xm::tm time1' has initializer but incomplete type
这似乎是因为 utilA.h
在第 0 行使用了 struct tm
,但没有包含 time.h
,并且编译器在第 0 行处理 struct tm
作为前向声明,因此第 2 行的 struct tm
在第 0 行的 header 内解析为 xm::tm
。
那么C++标准是否将此struct tm
定义为一种函数参数类型作为前向声明?请帮助解释这一点,引用标准会有所帮助。
在第 0 行,您在 xm
命名空间内声明了一个名为 tm
的 class。是的,C++ 允许在 function/template 参数中声明类型。
N4140 § 3.4.4 [basic.lookup.elab]/2
If the elaborated-type-specifier is introduced by the class-key and
this lookup does not find a previously declared type-name, or if the
elaborated-type-specifier appears in a declaration with the form:
class-key attribute-specifier-seqopt identifier;
the elaborated-type-specifier is a declaration that introduces the
class-name as described in 3.3.2.
因为您在 xm
命名空间内声明了一个名为 tm
的 class,它是名称查找在第 3 行为 tm
找到的第一个名称。::tm
(和::std::tm
)不被考虑。由于没有 class ::xm::tm
的定义,编译器抱怨它是一个不完整的类型。
如果你不是用 C++ 编写 C 代码,你会写类似1
struct tm;
namespace xz{
void zoo(tm timeval);
}
或
#include <ctime>
namespace xz{
void zoo(tm timeval);
}
你不会有那个问题。
1 请记住,您不能在命名空间 std
中转发声明名称
So does C++ standard define this struct tm
as an type of function parameter as forward declaration. Please help to explain this and quota from the standard will helpful.
是的,struct tm timeval
将在这里介绍一个新的class名称xm::tm
。
(解释和引用)
struct tm
是一个 elaborated type specifier,可用于引入新的 class 名称。
.1/4 Declarations and definitions [basic.def]
[ Note: A class name can also be implicitly declared by an elaborated-type-specifier ([dcl.type.elab]). — end note ]
.1/2 Class names [class.name]:
A declaration consisting solely of class-key identifier; is either a
redeclaration of the name in the current scope or a forward
declaration of the identifier as a class name. It introduces the class
name into the current scope.
.4.4/2 Elaborated type specifiers [basic.lookup.elab]:
or if the elaborated-type-specifier appears in a declaration with the
form:
class-key attribute-specifier-seqopt identifier ;
the elaborated-type-specifier is a declaration that introduces the
class-name as described in [basic.scope.pdecl].
.3.2/7 Point of declaration [basic.scope.pdecl]:
if the elaborated-type-specifier is used in the decl-specifier-seq or
parameter-declaration-clause of a function defined in namespace scope,
the identifier is declared as a class-name in the namespace that
contains the declaration;
对于struct tm timeval
用作函数参数声明,因为<time.h>
没有被包含并且还没有class命名为tm
,class tm
将在当前范围内声明(即命名空间 xm
),然后 xm::tm
将被向前声明。
我将在 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 在编译时报错 utilA.cpp,
error: variable 'xm::tm time1' has initializer but incomplete type
这似乎是因为 utilA.h
在第 0 行使用了 struct tm
,但没有包含 time.h
,并且编译器在第 0 行处理 struct tm
作为前向声明,因此第 2 行的 struct tm
在第 0 行的 header 内解析为 xm::tm
。
那么C++标准是否将此struct tm
定义为一种函数参数类型作为前向声明?请帮助解释这一点,引用标准会有所帮助。
在第 0 行,您在 xm
命名空间内声明了一个名为 tm
的 class。是的,C++ 允许在 function/template 参数中声明类型。
N4140 § 3.4.4 [basic.lookup.elab]/2
If the elaborated-type-specifier is introduced by the class-key and this lookup does not find a previously declared type-name, or if the elaborated-type-specifier appears in a declaration with the form:
class-key attribute-specifier-seqopt identifier;
the elaborated-type-specifier is a declaration that introduces the class-name as described in 3.3.2.
因为您在 xm
命名空间内声明了一个名为 tm
的 class,它是名称查找在第 3 行为 tm
找到的第一个名称。::tm
(和::std::tm
)不被考虑。由于没有 class ::xm::tm
的定义,编译器抱怨它是一个不完整的类型。
如果你不是用 C++ 编写 C 代码,你会写类似1
struct tm;
namespace xz{
void zoo(tm timeval);
}
或
#include <ctime>
namespace xz{
void zoo(tm timeval);
}
你不会有那个问题。
1 请记住,您不能在命名空间 std
中转发声明名称So does C++ standard define this
struct tm
as an type of function parameter as forward declaration. Please help to explain this and quota from the standard will helpful.
是的,struct tm timeval
将在这里介绍一个新的class名称xm::tm
。
(解释和引用)
struct tm
是一个 elaborated type specifier,可用于引入新的 class 名称。
.1/4 Declarations and definitions [basic.def]
[ Note: A class name can also be implicitly declared by an elaborated-type-specifier ([dcl.type.elab]). — end note ]
.1/2 Class names [class.name]:
A declaration consisting solely of class-key identifier; is either a redeclaration of the name in the current scope or a forward declaration of the identifier as a class name. It introduces the class name into the current scope.
.4.4/2 Elaborated type specifiers [basic.lookup.elab]:
or if the elaborated-type-specifier appears in a declaration with the form:
class-key attribute-specifier-seqopt identifier ;
the elaborated-type-specifier is a declaration that introduces the class-name as described in [basic.scope.pdecl].
.3.2/7 Point of declaration [basic.scope.pdecl]:
if the elaborated-type-specifier is used in the decl-specifier-seq or parameter-declaration-clause of a function defined in namespace scope, the identifier is declared as a class-name in the namespace that contains the declaration;
对于struct tm timeval
用作函数参数声明,因为<time.h>
没有被包含并且还没有class命名为tm
,class tm
将在当前范围内声明(即命名空间 xm
),然后 xm::tm
将被向前声明。