2010-11-12 3 views
7

Lors de la construction d'un petit exemple de programme avec Microsoft VisualStudio 2008, j'ai remarqué une chose étrange au sujet de la déduction des types passés aux modèles. Considérez cet exemple:Pourquoi les qualificatifs des arguments de modèle sont-ils supprimés lors de la déduction du type?

template<class T> 
void f(T v) { 
    x; // trigger a compile error 
    (void)v; 
} 

template<class T> 
void g(T v) { 
    f(v); 
} 

void h() { 
    int i; 
    g<const int &>(i); 
} 

cet exemple en utilisant Compiler cl /c foo.cpp engendre une erreur de compilation (comme prévu). Ce qui est intéressant, c'est la valeur du paramètre de template 'T'. Voici ce que VisualStudio 2008: impressions

mini.cpp(3) : error C2065: 'x' : undeclared identifier 
     mini.cpp(9) : see reference to function template instantiation 'void f<int>(T)' being compiled 
     with 
     [ 
      T=int 
     ] 
     mini.cpp(14) : see reference to function template instantiation 'void g<const int&>(T)' being compiled 
     with 
     [ 
      T=const int & 
     ] 

Notez comment dans g, le type de l'argument est const int & mais f il est juste int. Apparemment, la partie reference-to-const a été supprimée tout en déduisant le type à utiliser lors de l'instanciation du modèle f. Lors du réglage de l'exemple pour que f est appelé comme

f<T>(v); 

le type est const int & dans les deux f et g. Pourquoi donc? Est-ce un comportement spécifié? Je me suis secrètement appuyé sur le type de l'argument de la fonction v à passer à f mais apparemment ce n'est pas le cas.

+0

'Modèles C++' + MSVC++ = Mauvaise combinaison. –

+2

@Prasoon: GCC en déduit le même type.Bien sûr, dans GCC, le code du questionneur déclenche une erreur de compilation dans 'f' le modèle, avant qu'il ne soit presque question de l'instancier, car GCC effectue correctement la compilation en deux phases. 'x' ne dépend pas d'un paramètre de template, donc devrait être rejeté dans la première phase (comme dans GCC), pas dans la seconde (comme dans MSVC). Mais changez 'x' en' v = 1; ', et il est facile de voir que GCC n'instancie' f' avec 'const int &' que si vous spécifiez explicitement 'f (v)' in 'g'. –

Répondre

6

La réponse est que, bien que la v variable a de type const int &, l'expression v est une expression lvalue de type const int. Litb fournit le texte (5/6): "Si une expression a initialement le type" référence à T "(8.3.2, 8.5.3), le type est ajusté à" T "avant toute autre analyse , l'expression désigne l'objet ou la fonction désigné par la référence, et l'expression est une valeur lvalue. " Un "argument" est "une expression dans la liste séparée par des virgules délimitée par les parenthèses dans une expression d'appel de fonction" (1.3.1). Donc, dans 14.8.2.1:

  • "le type d'argument correspondant de l'appel (appelez-le A)" est const int.
  • "Si A est un type qualifié cv, les qualificatifs cv de niveau supérieur de type A sont ignorés pour la déduction de type" (par conséquent, int).
  • « le processus de déduction tente de trouver des valeurs d'argument modèle qui fera la déduit A identique à A » (si T est int)
+0

vous avez probablement raison. La terminologie standard avec A et P m'a complètement confus = | – icecrime

+0

@icecrime: moi aussi, ça ne fait pas partie du standard que je connais. Je pense que les ajustements à "P" signifient que si 'f' était déclaré' template void f (const T v) ', ou' template void f (T & v) ', alors T serait utilisé pour la déduction de type. Je ne suis pas sûr de bien le comprendre, cependant. –

+0

Même si ce n'est pas correct à 100%, c'est assez proche. "Evidemment" si nous regardons l'expression "v + v", tout le monde s'attendrait à ce qu'il se comporte comme une addition d'entier. Là, cela n'a pas de sens de traiter 'int &' différemment de 'int'. – MSalters

1

http://accu.org/index.php/journals/409 est un article assez vaste, mais il explique le processus. À partir des paramètres du modèle, un type de paramètre est dérivé et correspond à un type d'argument A. La partie pertinente est où elle décrit comment un type cible A est dérivé de l'argument de la fonction: pour les types non-tableau, les références sont simplement supprimées. Par conséquent, si le type de l'argument est int&, le type de cible A est simplement int.

C'est la raison simple: parce que le standard nous le dit. Quelle est la raison? En l'occurrence, l'article est accompagné d'une note de bas de page. Dans votre exemple, typeid(v)==typeid(const int). Lorsqu'ils sont utilisés dans des contextes non-lvalue, les types de référence se comportent comme des types sans référence.

Questions connexes