Любопытно взаимно повторяющиеся определения классов

Я хочу, чтобы объявления типов в двух классах взаимно зависели друг от друга. Вот первый пример, который компилируется как с clang, так и с gcc:

template <class Sum>
struct A
{
    using X = char;                // (1)
    using Z = typename Sum::B::Y;  // (2)
};

template <class Sum>
struct B
{
    using Y = typename Sum::A::X;
};

struct AplusB
{
    using A = ::A<AplusB>;
    using B = ::B<AplusB>;
};

AplusB::A::Z z;

int main() {}
Тем не менее, есть интересный момент. Если вы меняете строки (1) и (2), то он не скомпилируется с ошибкой:

error: нет имени с именем "X" в "A"

Это заставляет меня сомневаться, действительно ли исходный код действителен в смысле стандарта С++, или просто так происходит компиляция?

Вот второй пример, который также использует порядок создания экземпляра шаблона:

template <class Sum>
struct A
{
    using X = char;
    using P = typename Sum::B::Q;
};

template <class Sum>
struct B
{
    using Y = typename Sum::A::X;
    using Q = int;
};

struct AplusB
{
    using A = ::A<AplusB>;
    using B = ::B<AplusB>;
};

AplusB::A::X z; // (1)
AplusB::B::Q t; // (2)

int main() {}

Здесь, если вы замените (1) и (2), он не скомпилируется с ошибкой:

ошибка: тип типа 'Q' в 'B'

Итак, возникает вопрос: действительно ли это разрешено стандартом для определений классов, которое зависит друг от друга?

Ответы