在详细说明的类型说明符中首先声明的类的声明点如下:
(7.1)声明表格
class-key attribute-specifier-seqopt identifier
;
标识符在包含声明的作用域中声明为类名,否则
(7.2)表格的详细说明
类密钥标识符
如果在decl-specifier-seq中使用了elaborated-type-specifier 在命名空间范围内定义的函数的parameter-declaration-clause,标识符在包含声明的命名空间中声明为类名;否则,除了作为友元声明之外,标识符在包含声明的最小命名空间或块范围中声明。 [注意:这些规则也适用于模板。 - 尾注] [注意:其他形式的elaborated-type-specifier不声明新名称,因此必须引用现有的类型名称。参见[basic.lookup.elab]和[dcl.type.elab]。 - 结束说明]
考虑上面的情况(7.2),其中elaborated-type-specifier用在命名空间作用域中定义的函数的parameter-declaration-clause的decl-specifier-seq中。如何解释这个详细的类型说明符必须是其命名空间中类的第一个声明这一事实?
考虑下面的例子(demo):
文件prog.cc
:
struct S;
extern S s;
int S;
void f(struct S&); // The elaborated-type-specififer `struct S` is not
// the first declaration in the global namespace and
// if we eliminate the first declaration `struct S;`
// on the top, the code doesn't compile !!
int main(){
f(s);
}
文件other.cc
:
#include<iostream>
struct S{
int i = 1;
};
void f(struct S& s) { std::cout << s.i << '\n'; }
S s;
请注意,上面的代码正确编译和执行,但函数f
的parameter-declaration-clause中的elaborated-type-specififer不是全局命名空间中的第一个。
假设我对[basic.scope.pdecl] / 7的解释是正确的,我想看一个显示上面第(7.2)段的应用的例子,其中所提到的声明将是其命名空间中的第一个。
如果我们消除顶部的第一个声明
struct S;
,代码不编译!!
那是因为你还需要在使用前声明一个名字。
int S;
void f(struct S&);
extern struct S s; // If you write this line before then it
// will not compile.
// The name still needs to be declared
// before you use it.
// If you drop the `int S` above, then the following
// will also compile, since S has already been declared
// extern S s2;
int main(){
f(s);
}
请注意,上面的代码正确编译和执行,但函数
f
的parameter-declaration-clause中的elaborated-type-specififer不是全局命名空间中的第一个。
我不明白你想在这里提出的观点。因为它不是第一个,所以没有声明名称,并且[basic.scope.pdecl] p7不适用。
我想看一个例子,显示上面第(7.2)段的应用,其中所提到的声明将是其命名空间中的第一个。
auto addrof(struct S& s) { // First declaration
return &s;
}
int get(struct T&); // First declaration
我想看一个例子,显示上面第(7.2)段的应用,其中所提到的声明将是其命名空间中的第一个。
只是:
namespace ns {
// declares S into ns as per [basic.scope.pdecl]
void f(struct S&);
}
extern ns::S s;
//extern ::S s; // not declared
这里struct S
首先在名称空间作用域中定义的函数的参数声明子句中的elaborated-type-specifier中声明,形式为class-key identifier
,因此[basic.scope.pdecl] /7.2适用,并且struct S
在声明函数的名称空间ns
。
你将不得不在你的函数
S
中使用类f
的对象
这是一个example:
// ... continuing from previous example ...
namespace ns {
struct S {
int i;
};
void f(S& s) {
std::cout << s.i;
}
}
作为奖励,一个示例,其中类首先未在详细类型说明符中声明,因此引用的规则不适用:
struct S;
namespace ns {
void f(struct S&); // refers to ::S
}
//extern ns::S s; // not declared
extern ::S s;
这里,elaborated-type-specifier不是struct S
的第一个声明,因此[basic.scope.pdecl] / 7不适用,并且没有类被声明到命名空间中。