J'aime donner des erreurs / messages utiles, et je veux également le faire pour mes static_assert
. Le problème, c'est qu'ils dépendent des paramètres de modèle. Normalement, ces paramètres seront affichés d'une manière ou d'une autre en raison de l'erreur levée, mais ils sont soit obscurs, soit non regroupés pour qu'ils aient du sens. Exemple:
template
struct fake_dependency{
static bool const value = false;
};
template
struct Foo{
Foo(){}
template
Foo(Foo const&){
static_assert(fake_dependency::value, "Impossible de créer Foo à partir de Foo.");
}
};
int main(){
Foo fA;
Foo fB(fA);
}
Sortie sur MSVC:
src\main.cpp(74): error C2338: Impossible de créer Foo à partir de Foo.
src\main.cpp(84) : voir la référence à l'instanciation de modèle de fonction 'Foo::Foo(const Foo &)' en cours de compilation
with
[
T=int,
Tag=main::TagB
]
Un tag est mentionné dans le modèle de fonction lui-même, l'autre ci-dessous avec le modèle de classe. Pas très agréable. Voyons ce que GCC produit:
prog.cpp: Dans le constructeur 'Foo::Foo(const Foo&) [avec OtherTag = main()::TagA, T = int, Tag = main()::TagB]':
prog.cpp:18:32: instancié à partir d'ici
prog.cpp:12:5: erreur: assertion statique échouée: "Impossible de créer Foo à partir de Foo."
Beaucoup mieux, mais pas vraiment là où se trouve le static_assert
. Et maintenant imaginez encore plus de paramètres, ou plus de modèles, ou les deux. frissons
Une façon de contourner cela est d'utiliser une structure intermédiaire, qui prend les deux Tags en tant que paramètres de modèle:
template
struct static_Foo_assert{
static_assert(fake_dependency::value, "Impossible de créer Foo à partir de Foo.");
};
template
struct Foo{
Foo(){}
template
Foo(Foo const&){
static_Foo_assert x;
}
};
Voyons maintenant la sortie à nouveau:
src\main.cpp(70): error C2338: Impossible de créer Foo à partir de Foo.
src\main.cpp(79) : voir la référence à l'instanciation du modèle de classe 'static_Foo_assert' en cours de compilation
with
[
Tag=main::TagB,
OtherTag=main::TagA
]
Beaucoup mieux! Voici ce que GCC dit:
prog.cpp: Lors de l'instantiation de 'static_Foo_assert':
prog.cpp:17:40: instancié à partir de 'Foo::Foo(const Foo&) [with OtherTag = main()::TagA, T = int, Tag = main()::TagB]'
prog.cpp:23:32: instancié à partir de ici
prog.cpp:8:5: erreur: assertion statique échouée: "Impossible de créer Foo à partir de Foo."
Ça ne semble pas mal. Le problème: je dois créer une telle structure pour chaque modèle, car le message d'erreur dans static_assert
doit être un littéral de chaîne...
Maintenant, pour ma question: Pouvons-nous inclure d'une manière ou d'une autre les noms de type directement dans le static_assert
? Par exemple
static_assert(..., "Impossible de créer Foo<" T "," Tag "> à partir de Foo<" T "," OtherTag ">.");
Exemple de sortie:
Impossible de créer
Foo
à partir deFoo
.
Ou, si cela n'est pas réalisable, pouvons-nous d'une manière ou d'une autre rendre le message d'erreur un paramètre de modèle supplémentaire, pour le rendre transmissible?
11 votes
Je voudrais voir les compilateurs devenir meilleurs ici. Il doit être possible de montrer la condition qui a échoué. Il pourrait dire
note: dans la vérification static_assert pour fake_dependency::value [avec T = ...]
(entre crochets, il énumère tous les paramètres de modèle utilisés dans l'expression). Espérons !0 votes
@Johannes: Je pense que cela pourrait être fait avec les modèles d'expression
constexpr
, tu ne trouves pas ? Comme vous pouvez déjà disséquer les expressions / conditions d'exécution comme le fait le framework de test unitaire Check.0 votes
C'est dommage que les concepts n'aient pas été intégrés dans C++0x, car cela aurait grandement réduit le besoin comme cela se présente actuellement
typeid
oudynamic_cast
sont la seule façon de déterminer le type et nécessitent tous deux une instance que vous n'avez pas avec un argument de modèle.1 votes
@AJ: En fait, l'opérateur
typeid
est parfaitement valable sur les types uniquement : par exempletypeid(int)
. Mais le problème est questatic_assert
veut une chaîne littérale. :(0 votes
Connaissez-vous tous vos types à l'avance ? Si c'est le cas, vous pouvez créer un modèle d'erreur avec des spécialisations pour chaque type.
0 votes
@Dean : Je peux éventuellement fabriquer à la main les modèles
invalid_use_of_<>
, pour chaque message que je veux, comme abusé ici, mais j'ai spécifiquement demandéstatic_assert
. :/0 votes
Ma réponse : stackoverflow.com/questions/13837668/…