2009-08-12 6 views
21

J'ai créé deux fonctions simples qui obtiennent des paramètres de modèle et une structure vide définissant un type:Pourquoi la déduction d'argument de modèle ne fonctionne-t-elle pas ici?

//S<T>::type results in T& 
template <class T> 
struct S 
{ 
    typedef typename T& type; 
}; 

//Example 1: get one parameter by reference and return it by value 
template <class A> 
A 
temp(typename S<A>::type a1) 
{ 
    return a1; 
} 

//Example 2: get two parameters by reference, perform the sum and return it 
template <class A, class B> 
B 
temp2(typename S<A>::type a1, B a2)//typename struct S<B>::type a2) 
{ 
    return a1 + a2; 
} 

Le type d'argument est appliqué au S struct pour obtenir la référence. Je les appelle avec des valeurs entières mais le compilateur ne peut pas déduire les arguments:

int main() 
{ 
    char c=6; 
    int d=7; 
    int res = temp(c); 
    int res2 = temp2(d,7); 
} 

erreur 1 erreur C2783: 'A température (S :: type)': ne pouvait pas déduire argument modèle pour 'A'

erreur 2 erreur C2783: 'B temp2 (S :: type, B)': ne pouvait pas déduire argument de modèle pour 'A'


Pourquoi cela se produit-il? Est-il si difficile de voir que les arguments du modèle sont char et int valeurs?

Répondre

27

Tout comme la première note, le nom de type est utilisé lorsque vous mentionnez un nom dépendant. Donc vous n'en avez pas besoin ici.


template <class T> 
struct S 
{ 
    typedef T& type; 
}; 

En ce qui concerne le modèle instanciation, le problème est que typename S<A>::type caractérise un contexte nondeduced pour A. Quand un paramètre de modèle est utilisé uniquement dans un contexte nondeduced (cas A dans vos fonctions), il est pas pris en considération pour la déduction d'argument de modèle. Les détails sont à la section 14.8.2.4 de la norme C++ (2003).

Pour faire votre travail d'appel, vous devez spécifier explicitement le type:


temp<char>(c); 
+2

bienvenue à SO. et +1 :) –

+0

J'ai édité la citation pendant un certain temps. Vous d'abord, donc +1 :) –

6

Il est ressemble contexte nondeduced. Selon C++ standard 14.8.2.4/4:

Les contextes nondeduced sont:

  • Le imbriqué-name-spécificateur d'un type qui a été spécifié à l'aide d'un -id qualifié.
  • un type qui est un modèle dans lequel l'ID une ou plusieurs des modèles arguments est une expression qui fait référence à un modèle de paramètres .

Lorsqu'un nom de type est spécifié d'une manière qui inclut un contexte non réduit, tous les types qui comprennent ce nom de type sont également non déduits. Cependant, un type composé peut inclure à la fois des types déduits et non-édités. [Exemple: Si un type est spécifié comme A<T>::B<T2>, les deux T et T2 ne sont pas réduites. De même, si un type est spécifié comme A<I+J>::X<T>, I, J et T ne sont pas réduites.Si un type est spécifié comme void f(typename A<T>::B, A<T>), le T dans A<T>::B n'est pas réduit mais le T dans A<T> est déduit. ]

+0

Pouvez-vous m'expliquer ceci en mots simples avec des exemples: 'Le spécificateur de nom imbriqué d'un type qui a été spécifié en utilisant un id qualifié. Je sais que le spécificateur de nom imbriqué est' X :: 'et id qualifié est celui qui a' :: 'comme préfixe, mais incapable de conclure ou de comprendre tout. Merci beaucoup :) –

+0

est-il comme '(** Le spécificateur de nom imbriqué d'un type **) qui a été spécifié en utilisant un id qualifié. 'ou' Le spécificateur de nom imbriqué d'un (** type qui a été spécifié en utilisant un ID qualifié. **) ' –

4

Déduction fonctionne en marche avant:

template <class T> void f(T); 

f(2); // can deduce int from T 

Pourquoi est-ce qui se passe?

Il ne fonctionne pas dans le sens arrière (votre exemple):

template <class A> void g(typename S<A>::type); 

est-il si difficile de voir que les arguments de modèle sont des valeurs omble chevalier et int?

La déduction de modèle peut faire des choses magiques (Turing-complètes), mais je ne pense pas que ce soit l'un d'entre eux.

Vous pouvez utiliser quelque chose comme (non testé):

template <class SA> void h(SA a1) 
{ 
    STATIC_ASSERT(same_type<SA, S<A>::type>::value); 
    typedef typename SA::type A; 

    ... 
} 

Utilisation de votre bibliothèque assert statique favori (Boost a deux).

+0

Et maintenant dans la STL aussi: http://en.cppreference.com/w/cpp/ language/static_assert – ibizaman

Questions connexes