2015-10-29 1 views
1

L'ordre partiel des gabarits de fonction contenant des packs de paramètres de gabarit est indépendant du nombre d'arguments déduits pour ces gabarits de paramètres de gabarit.Ordonnancement partiel de modèles de fonctions contenant des packs de paramètres de gabarit

template<class...> struct Tuple { }; 
template<   class... Types> void g(Tuple<Types ...>);  // #1 
template<class T1, class... Types> void g(Tuple<T1, Types ...>); // #2 
template<class T1, class... Types> void g(Tuple<T1, Types& ...>); // #3 

g(Tuple<>());      // calls #1 
g(Tuple<int, float>());   // calls #2 
g(Tuple<int, float&>());   // calls #3 
g(Tuple<int>());     // calls #3 

ci-dessus est cité de partial ordering of overload function templates. Je ne comprends pas pourquoi g(Tuple<int>()); // calls #3. Plus précisément, pourquoi ne peut-on appeler #2? Ce qui suit est mon raisonnement, s'il vous plaît signaler les erreurs:

Remarque: Je ne tiendrai pas compte #1 b/c il est bien expliqué here

Étape 1: Déduction et résolution de substitution et de surcharge viennent avec ceux-ci:

  • void (tuple < int>) [T1 = int, types est vide] # 2
  • void (tuple < int>) [T1 = Int est vide & Types] # 3

2 Etape : Transform deux modèles de fonction:

  • annuler g (tuple < C1 ... Pack1>);
  • void g (Tuple < C2, paquet2 & ...>);

Etape 3: Ceci est un contexte d'appel de fonction, les types sont les types de paramètres de fonction pour laquelle l'appel de fonction a des arguments:

  • Déduire Tuple < T1, Types ...> de Tuple < C2, paquet & ...> OK [T1 = C2; Types ... = Paquet & ...]
  • Déduit Tuple < T1, Types & ...> à partir de Tuple < C1, Pack1 ...>) OK? [T1 = C1; Qu'en est-il des types & ...? Peut-il être déduit de Pack1 ...? Est-référence a chuté ici?]

3) Si P est un type de référence, le type visé par P est utilisé pour la déduction. This semble bien. Si P a l'une des formes qui incluent une liste de paramètres de modèle < T> ou < I>, alors chaque élément Pi de cette liste d'arguments modèle est comparé à l'argument de modèle correspondant Ai de son A. Si le dernier Pi est un développement de pack, puis son modèle est comparé à chaque argument restant dans la liste d'arguments de modèle de A. Un pack de paramètres de fin qui n'est pas déduit autrement, est déduit à un pack de paramètres vide.

Step4: Si la dernière étape est correcte. Cela signifie que # 3 n'est pas plus spécialisé que # 2.Il est donc ambigu quant à quel modèle de fonction doit être résolu.

Mise à jour: Je crois avoir mal compris les citations pertinentes ci-dessus. Lorsque nous associons les paramètres de modèle dans P avec les arguments de modèle dans A, ils sont mis en correspondance verbatim, ce qui signifie que toutes les transformations et analyses effectuées sur fonction appel paramètres et arguments ne s'appliquent pas à nouveau lorsque nous faisons correspondre les paramètres/arguments de modèle P/A (actuellement appel de fonction paramètre/arguments). Alors il échouera en l'étape 3 ci-dessus pour déduire Tuple< T1, Types&...> de Tuple< C1, Pack1...>). Donc, #3 est plus spécialisé.

+0

Avez-vous essayé avec les dernières versions de divers compilateurs? – Walter

+0

J'ai essayé sur g ++ seulement. Où puis-je essayer d'autres compilateurs en ligne? – Rich

+0

jeter un oeil à http://melpon.org/wandbox/ –

Répondre

2

La première étape de la résolution de surcharge consiste à trouver tous les candidats. Pour l'appel g(Tuple<int>()), il y a trois candidats viables:

g(Tuple<int>); // #1: [Types = {int}] 
g(Tuple<int>); // #2: [T1 = int, Types = {}] 
g(Tuple<int>); // #3: [T1 = int, Types = {}] 

Tous les trois sont des candidats tout aussi viables du point de vue des séquences de conversion (depuis, bien sûr, ils prennent tous le même argument qui est une correspondance exacte pour l'entrée). Ils sont tous des spécialisations de modèle de fonction, donc nous ne pouvons pas différencier sur cette base non plus. Donc, il nous reste un ordre partiel de modèle de fonction. Nous synthétisons des types pour chacune des surcharges et essayons d'effectuer une déduction de gabarit avec nos types synthétisés contre chacune des autres surcharges. La comparaison la plus simple est (1) vs (2) et (1) vs (3). Là, nous avons [temp.deduct.partial]:

Si A a été transformé à partir d'un pack de paramètres de fonction et si P n'est pas un pack de paramètres, la déduction de type échoue.

Depuis nous transformons Types... en UniqA..., et le premier paramètre est T1, déduction de type échoue. Cela fait (2) et (3) à la fois plus spécialisé que (1). Alors maintenant nous comparons (2) et (3).

D'abord, pouvons-nous déduire (2) de (3)?

template <class T1, class... Types> void g(Tuple<T1, Types...>); 

g(Tuple<Uniq3, Uniq3Pack&...>()); 

Bien sûr, pas de problème T1 == Uniq3 et Types... == Uniq3Pack&.... , Nous essayons suivant l'autre sens:

template <class T1, class... Types> void g(Tuple<T1, Types&...>); 

g(Tuple<Uniq2, Uniq2Pack...>()); 

Cela échoue, car Uniq2Pack n'est pas un paquet de types de référence et Types&... est. Puisque la déduction ne réussit que dans une direction, cela fait (3) la surcharge plus spécialisée.

Comme c'est le dernier debout, (3) est le meilleur candidat viable. Cela peut sembler paradoxal, puisque nous ne l'appelons pas avec un type de référence, mais c'est toujours le meilleur choix.

+0

Concise et au point! Cela a également résolu l'autre question http://stackoverflow.com/q/33426328/1021388. La raison est finalement la même pour les deux. Merci! – Rich