为什么这是 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 将被向前声明。