2015-11-25 3 views
11

Według standardu C++,Wewnętrzna widoczność członkiem klasy

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

więc poniższy kod należy skompilować i rzeczywiście robi

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

Jednak gdybym odkomentowaniu linia definiująca funkcję składową void Foo::f(Bar), a następnie kod nie skompiluje się z błędem

error: 'Bar' has not been declared

Ponownie czytając standard wydaje się, że parametry funkcji nie są uważane za miejsca, w których klasa jest uważana za kompletną. Jednak nie ma to żadnego sensu. Czy możesz rzucić trochę światła, dlaczego nie mogę użyć Bar w parametrze funkcji (ale poza tym można go w pełni wykorzystać wewnątrz funkcji bez żadnych problemów) przed jej pełną definicją?

+0

My najlepiej zgadnąć, że sama funkcja jest "oceniana" po zakończeniu "struct Foo", dzięki czemu dostępna jest opcja 'Bar'. Na deklaracji funkcji musi on znać typ, aby móc wygenerować sygnaturę funkcji. Ten sam problem występuje podczas definiowania typedef po próbie użycia tego typu w deklaracji funkcji. – RedX

+0

To pytanie dotyczy raczej wyszukiwania nazw niż kompletności typu klasy. –

+0

@RedX and T.C., Widzę teraz, uważam, że masz rację. Jeśli możesz opublikować odpowiedź, chętnie ją zaakceptuję. – vsoftco

Odpowiedz

6

We wszystkich przypadkach wymienionych w 9.2[class.mem] Znając typ można odłożyć do czasu, aż klasa zostanie w pełni zdefiniowana. Możemy zobaczyć to uzasadnienie wymienione w defect report 643: Use of decltype in a class member-specification, które mówi:

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.

Jako T.C. wskazuje na to, że istnieją również kwestie związane z wyszukiwaniem, z którymi mamy do czynienia jako defect report 325: When are default arguments parsed? i defect report 1352. Im później jeden wspomina również tej samej techniki jest w stanie odłożyć do analizowania klasa jest pełna:

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.

2

Od standardzie 03 3.4.1/8 (bez zastrzeżeń wyszukiwanie nazw):

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.