2015-09-20 4 views
14

Рассмотрим следующий код:Почему встроенное объявление не является неполным типом?

struct Foo { 
    struct Bar; 
    Foo() 
    { 
     Bar bar; // Why isn't Bar an incomplete type?! 
    } 
    struct Bar {}; // Full definition 
}; 

// struct Bar {}; // fails to compile due to incomplete type 

int main() 
{ 
    Foo foo; 
} 

Она компилирует отлично под по меньшей мере, 2 составителей (gcc5.2, clang3.5). Мой вопрос:

  • Почему Bar не считается неполным типа в конструкторе Foo::Foo, как я вперед объявить его над конструктором, но полностью использовать его внутри конструктора?

Всякий раз, когда я двигаюсь Foo::Bar вне класса, другими словами Bar становится самостоятельным классом, я получаю ожидаемый

error: aggregate 'Foo::Bar bar' has incomplete type and cannot be defined

+2

Органы функций-членов действуют так, как если бы они были определены вне линии (т. Е. После определения класса). –

+0

Основная причина заключается в том, что компилятор может выполнять локальный поиск всех определений внутри класса, когда он определяет, как обращаться с каждым типом. Объем рассмотрен полностью, так как это всего лишь небольшая часть вашей программы, и ему не нужно полагаться на порядок объявлений в исходном коде. – tp1

ответ

8

В спецификации члена класса считается завершенным в функции органов, из проект C++ стандартный раздел 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

означает, что вы не должны даже направить объявить Bar (see it live):

struct Foo { 
    Foo() 
    { 
     Bar bar; 
    } 
    struct Bar {}; 
}; 

вперед объявлении может быть полезным в предотвращении нарушений раздела 3.3.7 paragraph 2 and 3.

+0

Спасибо! Что касается вашего последнего редактирования, кажется, мне нужно переслать объявление, когда у внутреннего класса есть другой спецификатор доступа. См. [this] (http://stackoverflow.com/a/32685194/3093378), если я удалю форвардную декларацию, код не будет компилироваться (проверен как с gcc, так и с clang). – vsoftco

+0

@vsoftco right, в этом конкретном случае он работает без прямого объявления, так как это не одно из мест, где класс считается полным, как определено в приведенном выше параграфе. –

+0

Спасибо, кристально чистый! – vsoftco

Смежные вопросы