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;
}
Live on Coliru
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?
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.
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.
Related
In the c++ standard it is specified that within the class member-specification (class body), the class can be considered completely-defined, but not for static data member initializer [class.mem]:
A class is considered a completely-defined object type (6.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, noexcept-specifiers, and default member initializers (including such things in
nested classes). Otherwise it is regarded as incomplete within its own class member-specification.
EDIT: This is a citation from N4687, wording has changed but I do not believe the meaning changed.
I was expecting such code to compile:
struct enum_like
{
static constexpr enum_like enum_member{};
};
Why such a definition disallowed by the C++ standard?
I believe compilers could proceed this way:
read member declaration, not definition until class definition closing brace. (Now the compiler has a completely defined class)
Analyse static data-member initializer (This way compilers have the constant definition of constexpr members)
Analyse other member definitions.
And then resolve recursions for static member intializer as is specified in [decl.init] for non static members!
This rule forbids problematic things like:
struct A {
static constexpr std::size_t N = sizeof(A);
char buffer[N+2];
};
[basic.lookup.unqual]/8
For the members of a class X, a name used in a member function body,
in a default argument, in an exceptions-pecification, in the
brace-or-equal-initializer of a non-static data member (9.2), or in the definition of a class member outside of the definition of X,
following the member’s declarator-id 31, 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),32 or
...
Footnote:
32) This lookup applies whether the member function is defined within
the definition of class X or whether the member function is defined
in a namespace scope enclosing X’s definition.
Am I right?
I don't see any reason to tie the footnote to bullet point 3. The only thing the footnote says is that member function defined in in-class fashion can "see" the whole class (as would be the case if it was defined in out-of-class fashion). It applies equally to all bullet points.
For example, footnote 32 reaffirms that this code is valid
struct S
{
void foo() { i = 42; }
int i;
};
I.e. that the definition of S::foo() can "see" the declaration of S::i even though S::i is declared below the definition of S::foo(). As you can immediately see, the above example has no nested classes and thus has nothing to do with bullet point 3.
The footnote does not mean "this statement is only true for bullet point 3".
It means "by the way, this statement is [also] true for bullet point 3, a slightly more complex scenario with which you may have had your doubts as to the fact so stated".
So, while you're not objectively wrong, this is not any sort of editorial problem either.
I was going to file a bug against GCC, but then realized that if my interpretation of the Standard is correct, it's a core language defect, not a compiler bug.
When a static data member of array type is defined outside class scope, identifiers in the array bound are looked up in class scope.
§9.4.2 [class.static.data] says "The initializer expression in the definition of a static data member is in the scope of its class (3.3.7)," but doesn't say anything about the declarator itself. It seems that this is the only name lookup context within a declarator.
§8.4.2 [dcl.array] doesn't mention the scope of the array bound, so by default the expression is evaluated in the enclosing scope, which is the namespace.
class X {
static int const size = some_complicated_metafunction<>::value;
static int arr[ size ];
};
// "size" should be qualified as "X::size", which is an access violation.
int X::arr[ size ] = {};
The problem is that if the array bound is not evaluated in class scope, there is no way to access private class members, and some_complicated_metafunction<> would have to be respecified. The array bound needs the same scope as the initializer, for essentially the same reason as the initializer. (Although not quite as strong, since constant expressions can always be recomputed, unlike the address of a private object.)
Am I missing something or is a DR in order?
I think the array bound in a member definition is in class scope. Standard 3.3.7/1:
The following rules describe the scope of names declared in classes.
...
5) The potential scope of a declaration that extends to or past the end of a class definition also extends to the regions defined by its member definitions, even if the members are defined lexically outside the class (this includes static data member definitions, nested class definitions, member function definitions (including the member function body and any portion of the declarator part of such definitions which follows the declarator-id, including a parameter-declaration-clause and any default arguments (8.3.6). ...
Here the declarator-id is X::arr.
The C++ Language Standard states the following concerning template components in the Standard Library:
The effects are undefined...if an incomplete type is used as a template argument when instantiating a template component, unless specifically allowed for that component (C++11 §17.6.4.8/2).
Does the following cause instantiation of the std::vector class template?
class X;
std::vector<X> f(); // Declaration only; we will define it when X is complete
To ask it another way, in the function declaration std::vector<X> f();, is std::vector instantiated with the argument X? Or, is std::vector<X> not instantiated until f() is odr-used or defined?
Likewise, does the following cause instantiation of the std::vector class template?
class X;
typedef std::vector<X> XVector; // We will complete X before we use XVector
While I use std::vector in these examples, the question applies equally to all templates.
§ 14.7.1\1 Implicit instantiation [temp.inst]
Unless a class template specialization has been explicitly
instantiated (14.7.2) or explicitly specialized (14.7.3), the class
template specialization is implicitly instantiated when the
specialization is referenced in a context that requires a
completely-defined object type or when the completeness of the class
type affects the semantics of the program. The implicit instantiation
of a class template specialization causes the implicit instantiation
of the declarations, but not of the definitions or default arguments,
of the class member functions, member classes, static data members and
member templates; and it causes the implicit instantiation of the
definitions of member anonymous unions. Unless a member of a class
template or a member template has been explicitly instantiated or
explicitly specialized, the specialization of the member is implicitly
instantiated when the specialization is referenced in a context that
requires the member definition to exist; in particular, the
initialization (and any associated side-effects) of a static data
member does not occur unless the static data member is itself used in
a way that requires the definition of the static data member to exist.
§ 8.3.5\9 Functions [dcl.fct]
Types shall not be defined in return or parameter types. The type of a
parameter or the return type for a function definition shall not be an
incomplete class type (possibly cv-qualified) unless the function
definition is nested within the member-specification for that class
(including definitions in nested classes defined within the class).
§ 3.1\2 Declarations and definitions [basic.def]
A declaration is a definition unless it declares a function without
specifying the function’s body (8.4), it contains the extern specifier
(7.1.1) or a linkage-specification25 (7.5) and neither an initializer
nor a function-body, it declares a static data member in a class
definition (9.4), it is a class name declaration (9.1), it is an
opaque-enum-declaration (7.2), or it is a typedef declaration (7.1.3),
a using-declaration (7.3.3), a static_assert-declaration (Clause 7),
an attribute-declaration (Clause 7), an empty-declaration (Clause 7),
or a using-directive (7.3.4).
It's only instantiated if it's required. I couldn't find a clear definition anywhere, but the second quote says that those declaratations are not definitions, which seems to be the same to me.
No, it does not instantiate the template. Mooing Duck's answer provides all the necessary quotes, but here is some analysis.
Instantiation, by default, cannot occur if nothing exists to require a completely-defined type (§14.7.1/1). Function definitions specifically require complete types (§8.3.5/9), but the question is whether some other part of the standard also requires this for other declarations.
But there's a special exception for definitions, which reveals that non-definition declarations really are different:
The type of a parameter or the return type for a function definition shall not be an incomplete class type (possibly cv-qualified) unless the function definition is nested within the member-specification for that class (including definitions in nested classes defined within the class).
What's special about function definitions inside member-specifications? Because a member-specification cannot declare the same function twice (§9.2/1), and member function bodies are processed after all member declarations (§3.3.7/1.1). Essentially, a nested member function definition is treated as a declaration during the first pass, and then a definition once the entire member-specification has been processed, and the class is complete (§9.2/2). And §8.3.5/9 specifies that an incomplete class is permissible for that first pass, but not the second.
It's pretty onerous to perform an exhaustive, definitive search of the Standard's rules for function declarations and instantiations. But this example, although limited to member functions and the completeness of the enclosing type, can reasonably be extended to other functions and types. In any case, it's pretty good evidence of a distinction.
class A {
public: enum class { HELLO, WORLD };
};
Having known that, inside a class, declaring a simple enum (rather than enum class) is a better idea, because it's already typed with the class identification. But still above statement is a valid C++0x signature. Now how to access an unnamed enum class outside ?
int i = A::HELLO; // error: ‘HELLO’ is not a member of ‘A’
Actually, that is not valid. The C++0x FDIS says (9.2p1)
Except when used to declare friends (11.3) or to introduce the name of a member of a base class into a derived class (7.3.3), member-declarations declare members of the class, and each such member-declaration shall declare at least one member name of the class.
In your case, no enumerator name is introduced into the class' scope and no enumeration name is introduced either. So, no member name at all is introduced by that member-declaration.
EDIT: And actually, there's a more direct prohibition of the enumeration declaration. 7.2p2:
The optional identifier shall not be omitted in the declaration of a scoped enumeration.