@GoranFlegar: я сказал, что я не адвокат по языку. Я представил обоснование, как я его вижу.

указан неверный код:

struct foo {
    struct bar;
    bar x;        // error: field x has incomplete type
    struct bar{ int value{42}; };
};

int main() { return foo{}.x.value; }

Это вполне понятно, так какfoo::bar считается неполным в точке, гдеfoo::x определено.

Однако, кажется, есть «обходной путь», который делает такое же определение класса действительным:

template <typename = void>
struct foo_impl {
    struct bar;
    bar x;        // no problems here
    struct bar{ int value{42}; };
};

using foo = foo_impl<>;

int main() { return foo{}.x.value; }

Этотработает&nbsp;со всеми основными компиляторами. У меня есть три вопроса по этому поводу:

Это действительно правильный код C ++ или просто причуды компиляторов?Если это допустимый код, есть ли в стандарте C ++ параграф, который касается этого исключения?Если это правильный код, почему первая версия (безtemplate) считается недействительным? Если компилятор может определить второй вариант, я не вижу причины, по которой он не смог бы определить первый вариант.

Если я добавлю явную специализацию дляvoid:

template <typename = void>
struct foo_impl {};

template<>
struct foo_impl<void> {
    struct bar;
    bar x;        // error: field has incomplete type
    struct bar{ int value{42}; };
};

using foo = foo_impl<>;

int main() { return foo{}.x.value; } 

Это еще разне компилируется.