Question

En lisant une autre question, je suis arrivé à un problème avec ordre partiel, que je réduis à l'épreuve cas suivant

template<typename T>
struct Const { typedef void type; };

template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1

template<typename T>
void f(T, void*) { cout << "void*"; } // T2

int main() {
  // GCC chokes on f(0, 0) (not being able to match against T1)
  void *p = 0;
  f(0, p);
}

Pour les deux modèles de fonction, le type de fonction de la spécialisation qui entre dans la résolution de surcharge est void(int, void*). Mais un ordre partiel (selon comeau et GCC) dit maintenant que le second modèle est plus spécialisé. Mais pourquoi?

Laissez-moi passer par ordre partiel et montrer où j'ai des questions. Peut Q être un type maquillé unique utilisé pour déterminer un ordre partiel selon 14.5.5.2.

  • paramètre liste Transformée de T1 (Q insérée): (Q, typename Const<Q>::type*). Les types des arguments sont AT = (Q, void*)
  • paramètre liste Transformée de T2 (Q insérée): BT = (Q, void*), qui sont également les types des arguments.
  • paramètre Liste non transformé pour T1: (T, typename Const<T>::type*)
  • paramètre Liste non transformé pour T2: (T, void*)

Depuis C ++ 03 sous-précise, j'ai utilisé l'intention que j'ai lu dans plusieurs rapports de défaut. La liste des paramètres ci-dessus transformé pour T1 (appelé AT par moi) est utilisé comme liste d'arguments pour 14.8.2.1 « Déduire arguments de modèle à partir d'un appel de fonction » .

14.8.2.1 n'a pas besoin de transformer AT ou se BT plus (comme, la suppression déclarateurs de référence, etc.), et va droit au 14.8.2.4, qui indépendamment pour chaque A / paire P ne déduction de type:

  • AT contre T2: { (Q, T) , (void*, void*) } . T est le seul paramètre de modèle ici, et il trouvera que T doit être Q. déduction Type succède trivialement pour AT contre T2.

  • BT contre T1: { (Q, T) , (void*, typename Const<T>::type*) } . Il trouvera que T est Q aussi ici. typename Const<T>::type* est un contexte déduit non, et il ne sera pas donc être utilisé pour en déduire quoi que ce soit.


Voici ma première question: Est-ce maintenant utiliser la valeur de T déduite pour le premier paramètre? Si la réponse est non, alors le premier modèle est plus spécialisé. Cela ne peut pas être le cas, parce que les deux CCG et Comeau disent que le deuxième modèle est plus spécialisé, et je ne crois pas qu'ils ont tort. Donc, nous supposons « oui », et insérer void* dans T. Le paragraphe (14.8.2.4) dit « La déduction se fait indépendamment pour chaque paire et les résultats sont ensuite combinés » et aussi «Dans certains contextes, cependant, la valeur ne participe pas à la déduction de type, mais utilise plutôt les valeurs des arguments de modèle qui ont été soit déduisent ailleurs ou explicitement spécifiés. » Cela ressemble à « oui » aussi.

Déduction réussit donc aussi, pour chaque paire A / P. Maintenant, chaque modèle est au moins aussi spécialisé que l'autre, parce que la déduction ne repose pas aussi sur les conversions implicites et a réussi dans les deux sens. En conséquence, l'appel devrait être ambigu.

Alors ma deuxième question: Maintenant, pourquoi les implémentations disent que le second modèle est plus spécialisé? Quel point ai-je méconnais?


Modifier : Je l'ai testé la spécialisation explicite et instanciation, et les deux, ces dernières versions du CCG (4.4) me dire que la référence à lala spécialisation est ambiguë, tandis qu'une ancienne version de GCC (4.1) ne dépasse pas cette erreur d'ambiguïté. Cela suggère que les versions récentes du CCG ont ordre partiel incompatibles pour les modèles de fonction.

template<typename T>
struct Const { typedef void type; };

template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1

template<typename T>
void f(T, void*) { cout << "void*"; } // T2

template<> void f(int, void*) { }
  // main.cpp:11: error: ambiguous template specialization 
  // 'f<>' for 'void f(int, void*)'
Était-ce utile?

La solution

Voici mon aller à ce sujet. Je suis d'accord avec Charles Bailey que la mauvaise étape est d'aller de Const<Q>::Type* à void*

template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1

template<typename T>
void f(T, void*) { cout << "void*"; } // T2

Les mesures que nous voulons prendre sont:

14.5.5.2/2

  

Étant donné deux modèles de fonction surchargée, que l'on est plus spécialisé que l'autre peut être déterminée en transformant chaque modèle à son tour et en utilisant la déduction des arguments (14.8.2) pour la comparer à l'autre.

14.5.5.2/3-b1

  

Pour chaque paramètre de modèle type, la synthèse d'un type unique et remplacer, pour chaque occurrence de ce paramètre dans la liste des paramètres de la fonction, ou une fonction de conversion de modèle, dans le type de retour.

À mon avis, les types sont synthétisés comme suit:

(Q, Const<Q>::Type*)    // Q1
(Q, void*)              // Q2

Je ne vois pas un libellé qui exige que le second paramètre synthétisé de T1 être void*. Je ne connais pas de précédent pour que dans d'autres contextes non plus. Le type Const<Q>::Type* est parfaitement type valide dans le système de type C ++.

Alors maintenant, nous effectuons les étapes de déduction:

T2 à T1

Nous essayons de déduire les paramètres de modèle pour T1 nous avons donc:

  • Paramètre 1: T est déduit à Q
  • Paramètre 2: contexte Nondeduced

Même si le paramètre 2 est un contexte non déduit, déduction a encore réussi parce que nous avons une valeur T.

T1 à T2

Déduire les paramètres du modèle pour T2 nous avons:

  • Paramètre 1: T est déduit à Q
  • Paramètre 2: void* ne correspond pas à Const<Q>::Type* si l'échec de la déduction
  • .

à mon humble avis, voici où la norme nous laisse tomber. Le paramètre ne dépend pas il est donc pas vraiment clair ce qui devrait arriver, cependant, mon expérience (basée sur une lecture louchait de 14.8.2.1/3) est que, même si le type de paramètre P ne dépend pas, le type argument A doit correspondre il.

Les arguments synthétisés de T1 peuvent être utilisés pour se spécialiser T2, mais pas vice versa. T2 est donc plus spécialisé que T1 et est donc la meilleure fonction.


UPDATE 1:

Juste pour couvrir le Poing au sujet Const<Q>::type étant vide. Prenons l'exemple suivant:

template<typename T>
struct Const;

template<typename T>
void f(T, typename Const<T>::type*) // T1
{ typedef typename T::TYPE1 TYPE; }

template<typename T>
void f(T, void*)                    // T2
{ typedef typename T::TYPE2 TYPE ; }

template<>
struct Const <int>
{
  typedef void type;
};

template<>
struct Const <long>
{
  typedef long type;
};

void bar ()
{
  void * p = 0;
  f (0, p);
}

Dans ce qui précède, Const<int>::type est utilisé lorsque nous exécuter les règles habituelles de résolution de surcharge, mais pas quand nous obtenons les règles de surcharge partielle. Il ne serait pas correct de choisir une spécialisation arbitraire pour Const<Q>::type. Il ne peut pas être intuitif, mais le compilateur est très heureux d'avoir un type synthasized de la forme Const<Q>::type* et de l'utiliser pendant la déduction de type.


MISE À JOUR 2

template <typename T, int I>
class Const
{
public:
  typedef typename Const<T, I-1>::type type;
};

template <typename T>
class Const <T, 0>
{
public:
  typedef void type;
};

template<typename T, int I>
void f(T (&)[I], typename Const<T, I>::type*)     // T1
{ typedef typename T::TYPE1 TYPE; }

template<typename T, int I>
void f(T (&)[I], void*)                           // T2
{ typedef typename T::TYPE2 TYPE ; }


void bar ()
{
  int array[10];
  void * p = 0;
  f (array, p);
}

Lorsque le modèle de Const est instancié avec une I de valeur, il s'instancie récursive jusqu'à I atteint 0. Ceci est lorsque le Const<T,0> de spécialisation partielle est sélectionné. Si nous avons un compilateur qui synthétise un certain type réel pour les paramètres de la fonction, alors quelle valeur choisir le compilateur pour l'index de tableau? Dites 10? Eh bien, ce serait bien pour l'exemple ci-dessus, mais il ne correspondrait pas à la Const<T, 10 + 1> de spécialisation partielle qui, sur le plan conceptuel au moins, entraînerait un nombre infini de instanciation récursive du primaire. Quelle que soit la valeur que nous pourrions modifier sélectionné la condition final soit que la valeur + 1, et nous aurions une boucle infinie dans l'algorithme de commande partielle.

Je ne vois pas comment l'algorithme de commande partielle pourrait correctement instancier Const pour trouver what type est vraiment.

Autres conseils

Edit: Après avoir étudié la mise en œuvre Clang (par Doug Gregor) de leur algorithme de classement partiel, je suis venu d'accord avec le reste des affiches que l'exemple original n'est pas « destiné » à être ambiguë - même si la norme ne soit pas aussi claire qu'elle pourrait l'être sur ce qui devrait se produire dans de telles situations. J'ai édité ce post pour indiquer mes pensées révisées (pour mon propre bénéfice et référence). En particulier l'algorithme de Clang a précisé que « typename Const<T>::type » ne se traduit pas « vide » lors de l'étape de commande partielle -. Et que chaque paire A / P est déduit indépendamment l'un de l'autre

Dans un premier temps je me suis demandé pourquoi ce qui suit a été jugée ambiguë:

        template<class T> void f(T,T*);  // 1

        template<class T> void f(T, int*); // 2

        f(0, (int*)0); // ambiguous

(The above is ambiguous because one cannot deduce f1(U1,U1*) from f2(T,int*), and going the other way, one cannot deduce f2(U2,int*) from f1(T,T*). Neither is more specialized.)

mais ce qui suit ne serait pas ambigu:

        template<class T> struct X { typedef int type; };
        template<class T> void f(T, typename X<T>::type*); // 3
        template<class T> void f(T, int*); // 2

(La raison pour laquelle on pourrait attendre qu'il soit ambigu si les conditions suivantes devait arriver:
 - f3(U1,X<U1>::type*) -> f3(U1, int*) ==> f2(T,int*) (deduction ok, T=U1)
 - f2(U2,int*) ==> f3(T, X<T>::type*) (deduction ok, T=U2 makes X<U2>::type* -> int*)
Si cela était vrai, ni l'un serait plus spécialisé que l'autre.)

Après avoir étudié l'algorithme de commande partielle de Clang il est clair qu'ils traitent « 3 » ci-dessus comme si elle était:

template<class T, class S> void f(T, S*); // 4

déduction de certains uniques 'U' contre 'typename X :: type' réussira -

  • f3(U1,X<U1>::type*) is treated as f3(U1, U2*) ==> f2(T,int*) (deduction not ok)
  • f2(U2,int*) ==> f3(T,S* [[X<T>::type*]]) (deduction ok, T=U2, S=int)

Et donc « 2 » est nettement plus spécialisé que « 3 ».

  

Transformée paramètre-liste pour T1 (Q   inséré): (Q, nomtype   :: Const type *). Les types de   arguments sont AT = (Q, void *)

Je me demande si cela est vraiment une simplification correcte. Lorsque vous le type Q LA SYNTHÈSE, êtes-vous autorisé à évoquer une spécialisation pour Const aux fins de déterminer l'ordre de specliazation modèle?

template <>
struct Const<Q> { typedef int type; }

Cela impliquerait que T2 est pas au moins aussi spécialisé que T1 parce qu'un paramètre void* ne correspond pas à la deuxième paramètre de T1 pour tous les paramètres de modèle donné.

Edit: S'il vous plaît ignorer ce message - Après avoir étudié l'algorithme de clangs pour la commande partielle mis en œuvre par Doug Gregor (même si elle est partiellement mis en œuvre de cette écriture - il semble que la logique qui est pertinente à la question de l'OP est mis en œuvre assez nettement ) - il apparaît comme si elle traite le contexte comme un autre Non déduits paramètre de modèle. Ce qui suggère que la surcharge avec l'explicite vide * argument devrait être la version la plus spécialisée et il devrait y avoir aucune ambiguïté. Comme d'habitude Comeau est correcte. Maintenant, en ce qui concerne le libellé de la norme qui définit clairement ce comportement - c'est une autre affaire ...

Depuis ce poste a également été affiché sur comp.lang.c ++ modéré, et semble causer une certaine confusion là aussi -. Je pensais que je poste ma réponse à ce groupe là aussi - puisque la discussion est évidemment pertinente à la question posée ici.

  

On Jul 25, 1:11 pm, Bart van Ingen Schenau <b...@ingen.ddns.info> wrote:

     

You are going one step too fast here. How do you know (and would the compiler know) that there is no specialisation of Const<Q> such that Const<Q>::type != void?

     

As far as I can see, the compiler would transform the parameter-list of A to: AT=(Q, <unknown>*). To call B with these parameters requires an implicit conversion (<unknown>* to void*) and therefore A is less specialised than B.

Je crois que cela est inexact. Lors de la vérification pour voir quelle fonction est plus spécialisée (pendant-ordre partiel), le compilateur transforme le paramètre liste (Q, void*) - à-dire qu'elle instancie la pertinente modèle (meilleure correspondance) et regarde à l'intérieur pour la valeur de « type » - dans ce cas, sur la base sur le modèle primaire, il sera vide *.

En ce qui concerne votre point concernant la spécialisation partielle - lors de la vérification des quel modèle est plus spécialisé que l'autre, le seul type qui peut être utilisé est le type unique généré - s'il y a d'autres spécialisations au point de l'instanciation de la déclaration (lorsque la résolution de surcharge est fait) ils seront considérés. Si vous les ajoutez plus tard, et ils devraient être sélectionné vous violez l'ODR (selon 14.7.4.1)

Les spécialisations partielles / explicites auront également considertaion pendant la formation de l'ensemble des candidats - mais cette fois en utilisant les types des arguments réels à la fonction. Si les meilleurs résultats spécialisation partielle correspondant (X) dans un type de fonction qui a une meilleure séquence de conversion implicite pour certaines paramètre, nous ne faisons jamais à la phase d'ordre partiel, et que fonction « mieux » sera être sélectionné (avant de le rendre à la partie phase de commande)

Voici un exemple avec des commentaires sur ce qui devrait se passer à diverses étapes:

    template<class T, bool=true> struct X;  // Primary

    template<class T> struct X<T,true> { typedef T type; };  // A
    template<> struct X<int*,true> { typedef void* type; };  // B


    template<class T> void f(T,typename X<T>::type); //1
    template<class T> void f(T*,void*); //2


    int main()
    {
      void* pv;
      int* pi;


      f(pi,pi);   
      // two candidate functions: f1<int*>(int*,void*),  f2<int>(int*,void*)
      // Note: specialization 'B' used to arrive at void* in f1
      // neither has a better ICS than the other, so lets partially order
      // transformed f1 is f1<U1>(U1,X<U1,true>::type) --> f1<U1>(U1,U1) 
      //       (template 'A' used to get the second U1)
      // obviously deduction will fail (U1,U1) -> (T*,void*)
      // and also fails the other way (U2*, void*) -> (T,X<T>::type)
      // can not partially order them - so ambiguity 




      f(pv,pv);  
      // two candidate functions: f1<void*>(void*,void*), f2<void>(void*,void*)
      // Note: specialization 'A' used to arrive at second void* in f1
      // neither has a better ICS than the other, so lets partially order
      // transformed f1 is f1<U1>(U1,X<U1>::type) --> f1<U1>(U1,U1) 
      //       (template 'A' used to get the second U1)
      // obviously deduction will fail (U1,U1) -> (T*,void*)
      // and also fails the other way (U2*, void*) -> (T,X<T>::type)
      // can not partially order them - so ambiguity again             

    }

Il est également intéressant de mentionner que si le modèle principal ne dispose pas d'une définition - alors SFINAE fonctionne pendant la phase de commande partielle, ne peut être déduit de l'autre, et l'ambiguïté devrait en résulter.

Aussi, si vous ajoutez un autre modèle qui conduirait à un autre match si le point de instantiation de l'une de ces fonctions est déplacé ailleurs dans l'unité de traduction violerez clairement l'ODR.

  

On Jul 25, 1:11 pm, Bart van Ingen Schenau <b...@ingen.ddns.info> wrote:

     

Tout d'abord, étant plus spécialisés signifie que ceux-ci sont moins types où   ce modèle peut être sélectionné par la résolution de surcharge.   Avec cela, les règles pour la commande partielle peuvent être résumés comme suit: Essayez de   trouver un type A tel que A peut être appelé mais B non, ou de surcharge   résolution préfère appeler A. Si ce type peut être trouvée, B est plus   spécialisée que A.

Aucun argument ici. Mais sur la base des règles telles qu'elles sont actuellement, l'exemple de l'OP doit être ambiguë.


Enfin, voici explicites, des réponses claires aux deux questions spécifiques soulevées par litb:

1) Est-ce que ce maintenant utiliser la valeur de T déduite pour le premier paramètre?
Oui - bien sûr, il faut, il fait la déduction des arguments de modèle - les « liens » doivent être maintenus.

2) Maintenant, pourquoi les implémentations disent que le second est plus spécialisé à la place?
Parce qu'ils ont tort;)

J'espère que cela pose la question au repos - S'il vous plaît laissez-moi know s'il y a quelque chose qui ne sait pas encore:)

Edit: litb a soulevé un bon point dans son commentaire - indiquant peut-être que le modèle principal sera toujours obtenir utilisé pour l'instanciation avec le type unique généré est trop forte une déclaration.
Il y a des cas où le modèle primaire ne sera pas appelé.
Ce que je veux dire est que lors de la commande partielle est survenant, un certain type unique généré est utilisé pour faire correspondre la meilleure spécialisation. Vous avez raison, il ne doit pas être le modèle principal. J'ai modifié la langue ci-dessus pour le faire. Il a également soulevé une question en ce qui concerne la définition d'un meilleur modèle correspondant après le point de instantiation. Ce sera une violation de l'ODR conformément à la section sur le point de instanciation.


  

La norme indique qu'une fois que les paires A / P sont créés (en utilisant les règles de transformation comme décrit dans l'temp.func.order) ils sont déduits les uns contre les autres à l'aide d'argument de retenue modèle (temp.deduct) - et que les poignées de section le cas des contextes non déduits, instancier le modèle et son type imbriqué, ce qui déclenche des points de instanciations. La section temp.point traite les violations ODR (le sens de la commande partielle ne devrait pas changer quels que soient les points de instantiation au sein d'une unité de traduction). Je ne suis toujours pas sûr où la confusion vient? - Faisal Vali il y a 1 heure [supprimer ce commentaire]

     

litb: « Notez que l'étape qui met Q dans Const :: type pour construire les arguments ne sont pas couverts par la règle explicitement SFINAE.   Les règles SFINAE travaillent avec déduction des arguments, mettre les paragraphes qui mettent Q dans la liste des paramètres de la fonction de modèle de fonction sont à 14.5.5.2.

Les règles SFINAE doivent être utilisées ici - comment pourraient-ils pas? Je pense qu'il est suffisamment impliqué - je ne nie pas qu'il pourrait être plus clair, et alors que j'invite le comité à préciser cela -. Je ne pense pas qu'il a besoin d'être clarifié pour interpréter votre exemple suffisamment

Permettez-moi de une façon de les relier. De (14.8.2): « Quand une liste explicite des arguments de modèle est spécifié, les arguments de modèle doivent être compatibles avec le liste des paramètres matrice et doit aboutir à un type de fonction valide, comme décrit ci-dessous; autrement déduction de type échoue "

De (14.5.5.2/3) « La transformation est utilisée: - Pour chaque paramètre de modèle de type, la synthèse d'un type unique et remplacer que pour chaque occurrence de ce paramètre dans la liste des paramètres de la fonction, ou une fonction de conversion de modèle, dans le type de retour ».

Dans mon esprit, la citation ci-dessus implique qu'une fois que vous « créer » types générés uniques pour chaque paramètre de modèle, la déclaration de fonction doit être instancié par implicitement explicitement fournissant les types uniques comme arguments de modèle à notre modèle de fonction. Si cela se traduit par un malade type de fonction, non seulement la transformation, mais plus important encore la déduction des arguments de modèle ultérieure nécessaire pour commander partiellement la fonction échoue.

De (14.5.5.2/4) « Utilisation de la liste des paramètres de fonction transformée, effectuer la déduction des arguments contre l'autre modèle de fonction. Le modèle transformé est au moins aussi spécialisé que l'autre si, et seulement si , la déduction réussit et les types de paramètres déduits sont une correspondance exacte (de sorte que la déduction ne repose pas sur les conversions implicites). "

Si la liste des paramètres de fonction transformée conduit à une substitution échec, alors nous savons que la déduction ne pouvait pas avoir réussi. Et puisque la déduction n'a pas réussi, il est aussi spécialisé que l'autre - qui est tout ce que nous devons savoir pour procéder en ordre partiel des deux.

  

litb: Je suis également pas sûr de ce qui se passe dans ce cas: template<typename T> struct A;   template<typename T> void f(T, typename A<T>::type); template<typename T> void f(T*, typename A<T>::type); sûrement,   que ça indended être un code valide, mais en faisant un type ::, il échouera car au   modèle de définition contexte, n'est pas encore défini"   A noter également qu'il n'y a pas de POI défini pour instanciation de modèle résultant de cette   sorte de substitution tout en essayant de déterminer un ordre (ordre partiel ne dépend pas   sur tout contexte. Il est une propriété statique de deux modèles de fonction impliqués).   Je pense que cela ressemble à un problème dans la norme qui doit être fixé.

Ok - je pense que je vois où nous voyons les choses différemment. Si je vous comprends bien, vous dites que comme ces modèles de fonction se déclarer, le compilateur est de garder une trace de l'ordre partiel d'entre eux, quelle que soit la résolution de surcharge jamais se déclenche pour sélectionner entre eux. Si tel est votre interprétation, alors je comprends pourquoi vous attendez le comportement ci-dessus que vous décrivez. Mais je ne pense pas que la norme exige jamais ou mandats que.

Maintenant, la norme est clair que l'ordre partiel est agnostique du type qui est utilisé pour appeler la fonction (je crois c'est ce que vous faites référence lorsque vous décrivez comme une propriété statique et être indépendante du contexte).

La norme est également clair qu'il ne se soucie que commande partielle sur les (ordre partiel invoque) entre des modèles de fonction au cours du processus de résolution de surcharge (13.3.3 / 1) si et seulement si elle ne pouvait pas choisir la meilleure fonction basée sur ICS ou de si l'on est un modèle et l'autre non. [Ordre partiel des spécialisations partielles de modèle de classe est une question distincte et dans mon esprit utilise le contexte pertinent (d'autres définitions de modèle) qui nécessite l'instanciation de cette classe.]

Ainsi, à mon avis, étant donné que les mécanismes de commande partielle des modèles de fonction est appelée lorsque la surcharge la résolution est effectuée, il doit utiliser une partie correspondante du cadre (définitions de modèle et spécialisations) disponible au moment où la résolution de surcharge est fait.

d'après mon interepretation, selon votre exemple en utilisant « struct modèle A » ci-dessus, le code est valide. L'ordre partiel ne se fait pas au contexte de définition. Mais si / quand vous arrive d'invoquer la résolution de surcharge entre les deux fonctions en attribuant un appel à f ((int *) 0,0) - et à ce moment-là lorsque le compilateur soit essaie de rassembler une déclaration de candidat ou commander en partie les (si elle arrive à l'étape-commande partielle) si une expression non valide ou les résultats du type dans le cadre du type de fonction, SFINAE nous aide et dit nous que la déduction de modèle ne fonctionne pas (en ce qui concerne la commande partielle, cela implique que l'on ne peut pas être plus spécialisé que l'autre si on ne pouvait même transformer le modèle).

en ce qui concerne POIS - si vous êtes convaincu, comme je suis, que les types de fonctions transformées sont censées représenter instanciations implicites à l'aide de listes d'arguments de modèle fourni explicitement (en utilisant les types générés uniquement) puis les guillemets standard suivants sont pertinents:

Pour 14.6.4.1/1 une spécialisation de modèle de fonction, une fonction de membre de spécialisation modèle ou une spécialisation pour une fonction membre ou un membre de données statiques d'un modèle de classe, si la spécialisation est implicitement instanciée car il est référencé à partir d'une autre spécialisation du modèle et le contexte dans lequel il est fait référence dépend d'un paramètre de modèle, le point de instanciation de la spécialisation est le point de instanciation de la spécialisation renfermant.

La façon dont je l'interprète est que le POI du type de fonction transformée et le type de fonction est la origianl même que le POI pour les fonctions créées par l'appel de fonction réelle.

  

litb: Comme ordre partiel est plutôt seulement   a property of the syntactic form of parameters (i.e "T*" against "T(*)[N]"),   Je voterais pour modifier la spécification (comme « si Q apparaît dans un spécificateur nom imbriqué de   un identifiant qualifié nommant un type, le type désigné est « Q »)   Ou dire que le type du nom est un autre t unique,ype.   This means that in template<typename T> void f(T, typename Const<T>::type*);   the argument list is (Q, R*), for example.   Same for template<typename T> void f(T*, typename ConstI<sizeof(T)>::type);   the arg lisst would be (Q*, R). A similar rule would be needed for non-type parameters, of course.   Je dois y penser et faire des cas de test pour voir si cela produirait ordonnancements naturel, cependant.

Aah - vous propose maintenant une solution qui résout l'ambiguïté en faveur de ce que nous attendons tous intuitivement - c'est un autre problème, et pendant que j'aime la direction dans laquelle vous en, comme vous, je voudrais moi aussi mettre un peu la pensée en elle avant de proclamer sa maniabilité.

Merci pour poursuivre la discussion. Je souhaite donc ne pas seulement vous limiter à placer des commentaires.

Comme vous pouvez modifier mes messages, s'il vous plaît ne hésitez pas à répondre dans le poste si cela est plus facile.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top