Круговая зависимость С++ - пространство имен vs struct
Пожалуйста, просветите меня. Почему это компилируется:
struct compiles
{
struct A;
struct B
{
B(const A &a) : member(a.member) { }
int member;
};
struct A
{
A(const B &b) : member(b.member) { }
int member;
};
};
пока это не так:
namespace doesnt
{
struct A;
struct B
{
B(const A &a) : member(a.member) { }
int member;
};
struct A
{
A(const B &b) : member(b.member) { }
int member;
};
}
(в MSVC 9.0)
Ответы
Ответ 1
В С++ класс scope является специальным. Любое объявление, которое продолжается до или после конца определения класса, автоматически распространяется на регионы, определенные его определениями (3.3.6 [basic.scope.class]).
Это означает, что в первом случае как первое объявление struct A
, так и полное определение struct A
видны в теле B
и его конструкторе.
Это не относится к области пространства имен, поэтому во втором случае a.member
в конструкторе B
является ошибкой, потому что определение struct A
еще не видно.
Ответ 2
Тело определения class
/struct
/union
обрабатывается сразу, что позволяет ссылаться на членов классов, определенных позже. A namespace
обрабатывается сверху вниз, а форвардное объявление struct A
не позволяет использовать его элементы без определения. Попробуйте переместить определение конструктора B
вне класса, чтобы вы могли поместить его после определения A
.
Ответ 3
[Также проверено с помощью g++ 4.2] Первый компилируется, потому что компилятор полностью отображает все типы, определенные в структуре, прежде чем компилировать вложенные структуры (подумайте о публичных встроенных методах, используя частные атрибуты, которые появляются позже в классе). В пространстве имен компилятор просто работает сверху вниз и не имеет специальных правил.
Ответ 4
оба будут компилироваться, если вы переместите реализации конструкторов в файл .cpp, где они должны быть в любом случае.