J'ai ces cours:
#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;
}
Lors de la compilation, a_m
n'est pas constructible par défaut mais l' a
est.
Lors du passage C
à:
struct C {
int i;
};
tout va bien.
Testé avec Clang 9.0.0.
C() {}
ça marche aussi.static_assert
inA
échoue, mais si vous construisez par défaut unT
intérieur deA
(par exemple, mettez un membreT t;
là-bas), cela fonctionne très bien. Une incohérence entre ce que le trait de type vous dit et ce qui est réellement possible ...const int x;
n'est pas valide sans initialiseur, uniquement en raisonconst
du comportement d'initialisation des types intégrés et de certains historique)Réponses:
Ceci est interdit à la fois par le texte de la norme et par plusieurs mises en œuvre majeures comme indiqué dans les commentaires, mais pour des raisons totalement indépendantes.
Premièrement, la raison "par le livre": le point d'instanciation de
A<C>
est, selon la norme, immédiatement avant la définition deB
, et le point d'instanciation destd::is_default_constructible<C>
est immédiatement avant cela:Puisqu'il
C
est clairement incomplet à ce stade, le comportement d'instanciationstd::is_default_constructible<C>
n'est pas défini. Voir toutefois le problème central 287 , qui modifierait cette règle.En réalité, cela a à voir avec le NSDMI.
= 0
pourrait en principe se référer à des choses quiB
ne sont pas encore déclarées, donc l'implémentation ne peut pas vraiment essayer de l'analyser jusqu'à ce qu'elle soit terminéeB
.C
aucun constructeur n'a été déclaré.A<C>
, elle pense queC
c'est incomplet.L'ensemble de ce domaine traitant des régions analysées avec retard est malheureusement sous-spécifié, avec des divergences de mise en œuvre. Cela peut prendre un certain temps avant d'être nettoyé.
la source
Comportement indéfini c'est:
la source
C
est terminé, maisB
ne l'est pas. EtB::C
dépend indirectement deB
.C
a un modèle de constructeur par défaut avec un SFINAE étrange qui peut changer les réponses s'ilB
est complété différemment, alors bien sûr, le trait en dépend.