简体   繁体   English

为什么这是C ++中的前向声明?

[英]Why is this a forward declaration in C++?

I will have the following code snippet in utilA.cpp: 我将在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 complains when compiling utilA.cpp, GCC在编译utilA.cpp时抱怨,

error: variable 'xm::tm time1' has initializer but incomplete type

It seems this is because the utilA.h is using struct tm in line 0, but without include the time.h , and the compiler treat the struct tm in line 0 as a forward declare, so the struct tm at line 2 is resolved as xm::tm inside the header at line 0. 这似乎是因为utilA.h在第0行使用struct tm ,但没有包含time.h ,编译器将第0行中的struct tm视为前向声明,因此第2行的struct tm被解析为第0行标题内的xm::tm

So does the C++ standard define this struct tm as an type of function parameter as forward declaration? 那么C ++标准是否将此struct tm定义为一种函数参数作为前向声明? Please help to explain this and quotes from the standard will helpful. 请帮助解释一下,标准中的引用会有所帮助。

In line 0, you declared a class named tm inside the xm namespace. 在第0行中,您在xm命名空间内声明了一个名为tm的类。 Yes, C++ allows declaring types in function/template parameters. 是的,C ++允许在函数/模板参数中声明类型。

N4140 § 3.4.4 [basic.lookup.elab]/2 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: 如果由类键引入了elaborated-type-specifier ,并且此查找未找到先前声明的类型名称 ,或者如果elaborated-type-specifier出现在具有以下形式的声明中:

class-key attribute-specifier-seq opt identifier ; class-key attribute-specifier-seq opt identifier ;

the elaborated-type-specifier is a declaration that introduces the class-name as described in 3.3.2. elaborated-type-specifier是一个声明,它引入了3.3.2中描述的类名。

Because you declared a class named tm inside the xm namespace, it's the first name that name lookup finds for tm in line 3. ::tm (and ::std::tm ) are not considered. 因为你宣布一个名为类tm里面xm命名空间,这是该名称查找发现的第一个名字tm在第3行::tm (和::std::tm )不考虑。 And since there's no definition of class ::xm::tm , the compiler complains about it being an incomplete type. 由于没有class ::xm::tm定义,编译器抱怨它是一个不完整的类型。

If you weren't writing C code in C++, you'd write something like 1 如果你不是用C ++编写C代码,你会写一些类似1的东西

struct tm;

namespace xz{
    void zoo(tm timeval);
}

or 要么

#include <ctime>

namespace xz{
    void zoo(tm timeval);
}

and you wouldn't have that problem. 你不会有这个问题。

1 remember that you cannot forward-declare names in namespace std 1 记住你不能在名称空间std中转发声明名称

So does C++ standard define this struct tm as an type of function parameter as forward declaration. 因此,C ++标准将此struct tm定义为一种函数参数作为前向声明。 Please help to explain this and quota from the standard will helpful. 请帮助解释这个和标准配额会有所帮助。

Yes, struct tm timeval will introduce a new class name xm::tm here. 是的, struct tm timeval将在这里引入一个新的类名xm::tm


(explanations and quotes) (解释和引用)

struct tm is a elaborated type specifier , which could be used to introduce a new class name. struct tm是一个精心设计的类型说明符 ,可用于引入新的类名。

$3.1/4 Declarations and definitions [basic.def] $ 3.1 / 4声明和定义[basic.def]

[ Note: A class name can also be implicitly declared by an elaborated-type-specifier ([dcl.type.elab]). [注意:类名也可以由elaborated-type-specifier([dcl.type.elab])隐式声明。 — end note ] - 结束说明]

$9.1/2 Class names [class.name] : $ 9.1 / 2班级名称[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. 它将类名引入当前范围。

$3.4.4/2 Elaborated type specifiers [basic.lookup.elab] : $ 3.4.4 / 2详细说明的类型说明符[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]. elaborated-type-specifier是一个声明,它引入了[basic.scope.pdecl]中描述的类名。

$3.3.2/7 Point of declaration [basic.scope.pdecl] : $ 3.3.2 / 7声明点[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; 如果在命名空间作用域中定义的函数的decl-specifier-seq或parameter-declaration-clause中使用了elaborated-type-specifier,则在包含声明的命名空间中将标识符声明为类名。

For struct tm timeval used as function parameter declaration, because <time.h> is not included and there's still no class named tm , class tm will be declared in current scope (ie namespace xm ), then xm::tm will be forward declared. 对于用作函数参数声明的struct tm timeval ,因为没有包含<time.h>并且仍然没有名为tm类,所以将在当前作用域(即名称空间xm )中声明类tm ,然后将xm::tm声明为前向声明。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM