Tengo esas clases:
#include <type_traits>
template <typename T>
class A {
public:
static_assert(std::is_default_constructible_v<T>);
};
struct B {
struct C {
int i = 0;
};
A<C> a_m;
};
int main() {
A<B::C> a;
}
Al compilar, a_m
no se puede construir por defecto, pero lo a
es.
Al cambiar C
a:
struct C {
int i;
};
todo esta bien.
Probado con Clang 9.0.0.
C() {}
esto también funciona.static_assert
inA
falla, pero si por defecto construyes unT
interior deA
(por ejemplo, pones un miembroT t;
allí), todo funciona bien. Una inconsistencia entre lo que es realmente posible el tipo de rasgo que está diciendo y lo que ...const int x;
no es válido sin un inicializador, simplemente debido alconst
comportamiento de inicialización de los tipos incorporados y algunos historia)Respuestas:
Esto no está permitido tanto por el texto del estándar como por varias implementaciones importantes como se señala en los comentarios, pero por razones completamente ajenas.
Primero, la razón "por el libro": el punto de instanciación de
A<C>
es, según el estándar, inmediatamente antes de la definición deB
, y el punto de instanciación destd::is_default_constructible<C>
es inmediatamente anterior a eso:Como
C
está claramente incompleto en ese punto, el comportamiento de la creación de instanciasstd::is_default_constructible<C>
no está definido. Sin embargo, vea el problema central 287 , que cambiaría esta regla.En realidad, esto tiene que ver con el NSDMI.
= 0
podría referirse en principio a cosasB
aún no declaradas, por lo que la implementación realmente no puede tratar de analizarlo hasta que haya terminadoB
.C
que no tiene un constructor declarado.A<C>
se crea una instancia , piensa queC
está incompleto.Toda esta área que se ocupa de las regiones analizadas de forma diferida es lamentablemente poco especificada, con la divergencia de implementación que la acompaña. Puede pasar un tiempo antes de que se limpie.
fuente
Comportamiento indefinido es:
fuente
C
está completo, peroB
no lo está. YB::C
depende indirectamente deB
.C
tiene una plantilla de constructor predeterminada con algunos SFINAE extraños que pueden cambiar las respuestas siB
se completa de manera diferente, entonces seguro, el rasgo depende de ello.