J'ai joué avec clang un moment, et je suis tombé sur "test / SemaTemplate / depend-template-recover.cpp" (dans la distribution clang) qui est censé fournir des conseils pour récupérer d'une erreur de template.
Le tout peut être facilement réduit à un exemple minimal:
template<typename T, typename U, int N> struct X {
void f(T* t)
{
// expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
t->f0<U>();
}
};
Le message d'erreur généré par clang:
tpl.cpp:6:13: error: use 'template' keyword to treat 'f0' as a dependent template name
t->f0<U>();
^
template
1 error generated.
... Mais j'ai du mal à comprendre où exactement on est censé insérer le template
mot - clé pour que le code soit syntaxiquement correct?
Réponses:
ISO C ++ 03 14.2 / 4:
Dans
t->f0<U>();
f0<U>
est une spécialisation de modèle de membre qui apparaît après->
et qui dépend explicitement du paramètre de modèleU
, donc la spécialisation de modèle de membre doit être préfixée partemplate
mot-clé.Alors changez
t->f0<U>()
pourt->template f0<U>()
.la source
t->(f0<U>())
aurait corrigé cela, comme je pensais que cela mettraitf0<U>()
en expression autonome ... eh bien, je pensais mal, il semble ...En plus des points que d'autres ont soulevés, notez que parfois le compilateur ne pouvait pas se décider et que les deux interprétations peuvent produire des programmes valides alternatifs lors de l'instanciation
#include <iostream> template<typename T> struct A { typedef int R(); template<typename U> static U *f(int) { return 0; } static int f() { return 0; } }; template<typename T> bool g() { A<T> a; return !(typename A<T>::R*)a.f<int()>(0); } int main() { std::cout << g<void>() << std::endl; }
Ceci s'imprime
0
lors de l'omissiontemplate
avantf<int()>
mais1
lors de son insertion. Je laisse cela comme un exercice pour comprendre ce que fait le code.la source
f<U>
et s'imprime toujours1
, ce qui me semble parfaitement logique. Je ne comprends toujours pas pourquoi letemplate
mot-clé est requis et quelle différence cela fait.template
est nécessaire: stackoverflow.com/questions/610245/… sans se fier uniquement à des termes standards difficiles à comprendre. Veuillez signaler si quelque chose dans cette réponse prête encore à confusion.Insérez-le juste avant le point où se trouve le curseur:
template<typename T, typename U, int N> struct X { void f(T* t) { t->template f0<U>(); } };
Edit: la raison de cette règle devient plus claire si vous pensez comme un compilateur.
Les compilateurs ne regardent généralement en avant qu'un ou deux jetons à la fois, et ne «regardent pas en avant» le reste de l'expression.[Modifier: voir le commentaire] La raison du mot-clé est la même que la raison pour laquelle vous avez besoin dutypename
mot - clé pour indiquer les noms de types dépendants: il dit au compilateur "hé, l'identifiant que vous êtes sur le point de voir est le nom d'un modèle, plutôt que le nom d'un membre de données statique suivi d'un signe inférieur à ".la source
template
. Il y a des cas où les deux avec et sanstemplate
donneront des programmes valides avec un comportement différent. Il ne s'agit donc pas seulement d'un problème de syntaxe (ilt->f0<int()>(0)
est syntaxiquement valide pour la version de la liste d'arguments inférieur à et du modèle).Extrait de modèles C ++
La construction .template Un problème très similaire a été découvert après l'introduction de typename. Prenons l'exemple suivant en utilisant le type de jeu de bits standard:
template<int N> void printBitset (std::bitset<N> const& bs) { std::cout << bs.template to_string<char,char_traits<char>, allocator<char> >(); }
La construction étrange dans cet exemple est .template. Sans cette utilisation supplémentaire du modèle, le compilateur ne sait pas que le jeton inférieur à (<) qui suit n'est pas vraiment «inférieur à» mais le début d'une liste d'arguments de modèle. Notez qu'il s'agit d'un problème uniquement si la construction avant la période dépend d'un paramètre de modèle. Dans notre exemple, le paramètre bs dépend du paramètre de modèle N.
En conclusion, la notation .template (et les notations similaires telles que -> template) ne doivent être utilisées qu'à l'intérieur des templates et uniquement si elles suivent quelque chose qui dépend d'un paramètre de template.
la source