Видимость внутреннего члена в классе
В соответствии со стандартом С++
9.2 [class.mem]:
Класс считается полностью определенным типом объекта (3.9) (или полный тип) при закрытии} спецификатора класса. В рамках класса, класс считается полным в пределах функциональные тела, аргументы по умолчанию, использование-объявления, представляющие наследующие конструкторы (12.9), спецификации исключений и скопированные или равные инициализаторы для нестатических членов данных (в том числе такие вещи во вложенных классах). В противном случае он считается неполным в пределах своей собственной спецификации члена класса
Итак, приведенный ниже код должен компилироваться, и действительно, он
struct Foo{
Foo()
{
Bar bar; // Bar is fully visible here, even though it defined later
}
//void f(Bar){} // But NOT VISIBLE if used as a function parameter
struct Bar{};
};
int main()
{
Foo foo;
}
Live on Coliru
Однако, если я раскомментирую строку, которая определяет функцию-член void Foo::f(Bar)
, тогда код не скомпилируется с ошибкой
ошибка: "Бар" не был объявлен
Снова повторив стандарт, действительно кажется, что параметры функции не считаются местами, где класс считается полным. Однако это не имеет никакого смысла. Можете ли вы пролить свет, почему я не могу использовать Bar
в параметре функции (но в противном случае может полностью использовать его внутри функцию без каких-либо проблем) до ее полного определения?
Ответы
Ответ 1
Во всех случаях, перечисленных в 9.2
[class.mem], зная, что тип может быть отложен до полного определения класса. Мы можем видеть это обоснование, перечисленное в отчет о дефекте 643: Использование decltype в спецификации члена класса, в котором говорится:
В других случаях, когда тип класса считается полным в определении класса, можно отложить обработку конструкции до конца определения. Это невозможно для типов, поскольку тип может понадобиться немедленно в последующих объявлениях.
Как T.C. указывает, что есть также проблемы поиска, связанные с отчет о дефекте 325: когда аргументы по умолчанию разобраны? и отчет о дефекте 1352. В более поздней части также упоминается одна и та же методика, позволяющая отложить парсинг до завершения класса:
Правила, касающиеся класса и когда класс считается полным (обычно реализуется отсроченным анализом частей деклараций членов класса), являются непоследовательными и нуждаются в уточнении.
Ответ 2
Из стандарта 03, 3.4.1/8 (поиск неквалифицированного имени):
Имя, используемое в определении функции-члена (9.3) класса X, следующего за функциями declarator-id 29) объявляется одним из следующих способов:
- перед его использованием в блоке, в котором он используется, или в закрывающем блоке (6.3), или
- должен быть членом класса X или быть членом базового класса X (10.2) или
- если X является вложенным классом класса Y (9.7), должен быть членом Y или быть членом базового класса Y (этот поиск применяется в свою очередь к Ys, охватывающим классы, начиная с самого внутреннего охватывающего класса), 30) или
- если X является локальным классом (9.8) или является вложенным классом локального класса, то до определения класса X в блоке включая определение класса X, или
- , если X является членом пространства имен N или является вложенным классом класса, который является членом N или является локальным классом или вложенный класс в локальном классе функции, являющейся членом N, до функции-члена определение в пространстве имен N или в одном из Ns, охватывающих пространства имен.