"Друг" класса распространяется на классы, объявленные в этом классе?

У меня есть следующий код, где класс A объявляет класс B как друга. Если класс C, объявленный в классе B, сможет просматривать частные объявления/члены класса A?

Он компилируется без ошибок с CL версии 16 (Visual Studio 2010), но gcc g++ version 4.1.1 дает ошибку "typedef int A:: T является конфиденциальной в этом контексте".

То же самое происходит с вызовами функций как typedefs (именно так я обнаружил разницу).

class A {
   friend class B;
   typedef int T;
};

class B {
   A::T t; // ok
   typedef A::T U; // ok
   class C {
      U u; // ok
      A::T v; // compile error on gcc
   };
};

Я коротко искал, но не смог найти правильные условия поиска. Я еще не прочитал стандарт. Есть ли какие-либо предыдущие вопросы по этому вопросу или упомянуты в FAQ на С++? Какое поведение накладывается стандартом, если либо?

Ответы

Ответ 1

Из стандартных документов., $11.4.2

Объявление класса как друга означает, что имена частных и защищенных членов из класса, предоставляющего дружбу можно получить в спецификаторе базового спецификатора s и объявлениях участников подрессоренного класса.

Пример из стандартных документов., сами,

class A {
class B { };
friend class X;
};
struct X : A::B { // OK: A::B accessible to friend
    A::B mx; // OK: A::B accessible to member of friend
    class Y {
        A::B my; // OK: A::B accessible to nested member of friend
    };
};

Следовательно, он должен работать без ошибок.

Ответ 2

Кажется, что некоторый дефект в исходном стандарте С++ 03

В соответствии с С++ 03 [pre CD1] ваш код не должен компилироваться, потому что формулировка и пример говорят, что закрытые члены класса (предоставление дружбы) не могут быть доступны во вложенном члене класса friend.

С++ 11 дает тот же пример, что и в С++ 03. Единственное изменение, внесенное в этот пример, заключается в том, что вложенный член (класс) класса friend может получить доступ к частному члену класса, предоставляющего дружбу.

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

Также смотрите вопроС# 45

Ответ 3

Prasoon упоминает проблему № 45... это поведение меняется в С++ 0x. Старое поведение было (11.7 [class.access.nest] абзац 1):

Члены вложенного класса не имеют специального доступа к членам охватывающего класса, а также к классам или функциям, которые предоставили дружбу окружающему классу.

Это ясно говорит о том, что gcc 4.1 является правильным в соответствии с правилами С++ 03. gcc 4.5 и MSVC2010 используют правила С++ 0x.