El tipo incompleto no está permitido en una clase, pero sí en una plantilla de clase

El siguiente es un código no válido:

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

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

Esto es bastante claro, ya quefoo::bar se considera incompleto en el punto dondefoo::x se define

Sin embargo, parece haber una "solución" que hace válida la misma definición de clase:

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

Estatrabajo con todos los principales compiladores. Tengo tres preguntas sobre esto:

Es este un código C ++ realmente válido, o simplemente una peculiaridad de los compiladores?Si es un código válido, ¿hay un párrafo en el estándar C ++ que aborde esta excepción?Si es un código válido, ¿por qué es la primera versión (sintemplate) considerado inválido? Si el compilador puede descubrir la segunda opción, no veo una razón por la cual no podría resolver la primera.

Si agrego una especialización 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; } 

Una vez más falla al compilar.

Respuestas a la pregunta(4)

Su respuesta a la pregunta