Tipo incompleto não é permitido em uma classe, mas é permitido em um modelo de classe

O código a seguir é inválido:

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

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

Isso é bem claro, poisfoo::bar é considerado incompleto no ponto em quefoo::x é definido.

No entanto, parece haver uma "solução alternativa" que torna válida a mesma definição de classe:

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; }

estetrabalho com todos os principais compiladores. Eu tenho três perguntas sobre isso:

É realmente um código C ++ válido ou apenas uma peculiaridade dos compiladores?Se for um código válido, existe um parágrafo no padrão C ++ que lide com essa exceção?Se for um código válido, por que a primeira versão (semtemplate) considerado inválido? Se o compilador puder descobrir a segunda opção, não vejo uma razão para não conseguir descobrir a primeira.

Se eu adicionar uma especialização explícita paravoid:

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; } 

Mais uma vezfalha ao compilar.

questionAnswers(2)

yourAnswerToTheQuestion