Why is this a forward declaration in C++?

若如初见. 提交于 2021-02-08 12:16:40

问题


I will have the following code snippet in 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,

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.

So does the C++ standard define this struct tm as an type of function parameter as forward declaration? Please help to explain this and quotes from the standard will helpful.


回答1:


In line 0, you declared a class named tm inside the xm namespace. Yes, C++ allows declaring types in function/template parameters.

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.

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. And since there's no definition of class ::xm::tm, the compiler complains about it being an incomplete type.

If you weren't writing C code in C++, you'd write something like1

struct tm;

namespace xz{
    void zoo(tm timeval);
}

or

#include <ctime>

namespace xz{
    void zoo(tm timeval);
}

and you wouldn't have that problem.

1remember that you cannot forward-declare names in namespace std




回答2:


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.

Yes, struct tm timeval will introduce a new class name xm::tm here.


(explanations and quotes)

struct tm is a elaborated type specifier, which could be used to introduce a new class name.

$3.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 ]

$9.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.

$3.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.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;

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 (i.e. namespace xm), then xm::tm will be forward declared.



来源:https://stackoverflow.com/questions/40257011/why-is-this-a-forward-declaration-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!