Декларация друга не будет объявлена

Я понимаю, что 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
}
Другие вопросы по тегам