根据C ++标准,
9.2 [class.mem]:
一个类被认为是一个完全定义的对象类型(3.9)(或 完成类型)在类说明符的结束时。内 class member-specification,该类被认为是完整的 函数体,默认参数,引用的使用声明 继承构造函数(12.9),异常规范和 用于非静态数据成员的括号或等于初始化器(包括 嵌套类中的这类东西)。否则它被认为是不完整的 在其自己的类成员规范
中
所以,下面的代码应该编译,确实是
struct Foo{
Foo()
{
Bar bar; // Bar is fully visible here, even though it's defined later
}
//void f(Bar){} // But NOT VISIBLE if used as a function parameter
struct Bar{};
};
int main()
{
Foo foo;
}
但是,如果我取消注释定义成员函数void Foo::f(Bar)
的行,则代码无法使用错误进行编译
错误:' Bar'尚未宣布
再次阅读标准确实似乎函数参数不被视为类被视为完整的地方。但是,它根本没有任何意义。您能否解释为什么我不能在函数参数中使用Bar
(但在其完全定义之前可以完全使用在函数中没有任何问题)?
答案 0 :(得分:6)
在9.2
[class.mem] 中列出的所有情况中,知道类型可以延迟到完全定义类之前。我们可以在defect report 643: Use of decltype in a class member-specification中找到这样的理由:
在类的定义中认为类类型完整的其他情况下,可以将处理构造推迟到定义的结尾。这对于类型是不可能的,因为在后续声明中可能需要立即使用类型。
作为T.C.指出在defect report 325: When are default arguments parsed?和defect report 1352处理时还存在查找问题。后者还提到了能够推迟解析直到课程完成的相同技术:
关于类范围的规则以及何时认为类是完整的(通常通过对类成员声明的部分进行延迟解析来实现)是不一致的,需要澄清。
答案 1 :(得分:2)
从03标准,3.4.1 / 8(非限定名称查找):
在函数的declarator-id 29 之后的类X的成员函数(9.3)的定义中使用的名称 应以下列方式之一宣布:
- 在使用它之前的块中或在封闭块(6.3)中,或
- 应该是X类成员或者是X(10.2)基类的成员,或者
- 如果X是Y类(9.7)的嵌套类,则应为Y的成员,或者是Y的基类的成员 (这个查找依次应用于Y的封闭类,从最里面的封闭类开始),30)或
- 如果X是本地类(9.8)或是本地类的嵌套类,则在块中定义类X之前 包含类X的定义,或
- 如果X是名称空间N的成员,或者是属于N的成员的类的嵌套类,或者是本地类 或者在成员函数之前,作为N的成员的函数的本地类中的嵌套类 定义,在命名空间N或N的封闭命名空间之一。