Reputation: 56567
According to the C++ standard,
9.2 [class.mem]:
A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification
So, the code below should compile, and indeed it does
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;
}
However, if I uncomment the line that defines the member function void Foo::f(Bar)
, then the code fails to compile with the error
error: 'Bar' has not been declared
Reading again the standard it indeed seems that function parameters are not considered as places where the class is regarded as complete. However, it does not make any sense at all. Can you shed some light why I cannot use Bar
in a function parameter (but otherwise can fully use it inside a function without any issues whatsoever) before its full definition?
Upvotes: 11
Views: 224
Reputation: 16945
From the 03 standard, 3.4.1/8 (Unqualified name lookup):
A name used in the definition of a member function (9.3) of class X following the function’s declarator-id29) shall be declared in one of the following ways:
— before its use in the block in which it is used or in an enclosing block (6.3), or
— shall be a member of class X or be a member of a base class of X (10.2), or
— if X is a nested class of class Y (9.7), shall be a member of Y, or shall be a member of a base class of Y (this lookup applies in turn to Y’s enclosing classes, starting with the innermost enclosing class),30) or
— if X is a local class (9.8) or is a nested class of a local class, before the definition of class X in a block enclosing the definition of class X, or
— if X is a member of namespace N, or is a nested class of a class that is a member of N, or is a local class or a nested class within a local class of a function that is a member of N, before the member function definition, in namespace N or in one of N’s enclosing namespaces.
Upvotes: 3
Reputation: 158539
In all the cases listed in 9.2
[class.mem] knowing the type can be deferred until the class is fully defined. We can see this rationale listed in defect report 643: Use of decltype in a class member-specification which says:
In the other cases where a class type is considered complete within the definition of the class, it is possible to defer handling the construct until the end of the definition. That is not possible for types, as the type may be needed immediately in subsequent declarations.
As T.C. points out there is also issues of lookup involved as defect report 325: When are default arguments parsed? and defect report 1352 deal with. The later one also mentions the same technique of being able to defer parsing till the class is complete:
The rules regarding class scope and when the class is considered to be complete (normally implemented by deferred parsing of portions of class member declarations) are inconsistent and need to be clarified.
Upvotes: 7