Декларация друга не будет объявлена
Я понимаю, что friend
объявление также может служить предварительным объявлением для класса, если class
был использован спецификатор, как в этом примере:
class A
{
friend class B;
B* b;
};
class B {};
int main() {}
Однако g++ (4.6.3 и 4.7.0) дает мне следующую ошибку (g++-4.7 должна иметь поддержку расширенных объявлений друзей), которая ожидается без предварительного уведомления:
main.cpp: 6: 2: ошибка: "B" не называет тип
В попытке подтвердить мои ожидания, что friend class B;
должен служить предварительным объявлением, я нашел этот ответ и этот ответ, но ни один из них не был окончательным (или я не мог сделать много выводов из них, по крайней мере), поэтому я попытался обратиться к стандарту C++11 и нашел этот пример:
class X2 {
friend Ct; // OK: class C is a friend
friend D; // error: no type-name D in scope
friend class D; // OK: elaborated-type-specifier declares new class
}
Исходя из моего прочтения третьей декларации, мой friend class B
должен быть подробным спецификатором типа, объявляющим новый класс.
Я только начинаю понимать официальную стандартную формулировку, поэтому я должен что-то упустить. Что я недопонимаю?
2 ответа
Ваш friend class B;
Объявление действительно служит предварительным объявлением, но такое объявление не найдено при поиске имени, пока не будет предоставлено соответствующее объявление.
[class.friend] / 11:
Если объявление друга появляется в локальном классе (9.8), а указанное имя является неквалифицированным именем, выполняется поиск предшествующего объявления без учета областей, которые находятся за пределами самой внутренней охватывающей области, не относящейся к классу. Для объявления функции-друга, если нет предварительного объявления, программа некорректна. Для объявления класса-друга, если нет предварительного объявления, указанный класс принадлежит к самой внутренней охватывающей области, не относящейся к классу, но если на него впоследствии ссылаются, его имя не будет найдено при поиске имени, пока не будет найдено соответствующее объявление в самая внутренняя вмещающая неклассная область.
Взгляните на 11.3 пункт 11:
Для объявления класса-друга, если нет предварительного объявления, указанный класс принадлежит к самой внутренней охватывающей области, не относящейся к классу, но если на него впоследствии ссылаются, его имя не будет найдено при поиске имени, пока не будет найдено соответствующее объявление в самая внутренняя вмещающая неклассная область.
Пример:
class X;
void a();
void f() {
class Y;
extern void b();
class A {
friend class X; // OK, but X is a local class, not ::X
friend class Y; // OK
friend class Z; // OK, introduces local class Z.
friend void a(); // error, ::a is not considered
friend void b(); // OK
friend void c(); // error
};
X *px; // OK, but ::X is found
Z *pz; // error, no Z is found
}