Frage

Während eines andere Frage zu lesen, ich kam zu einem Problem mit teilweise Ordnung, die ich den folgenden Test-Fall abgeholzt

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);
}

Für beide Funktionsschablonen, die Funktionsart der Spezialisierung, die Überladungsauflösung tritt void(int, void*) ist. Aber teilweise Ordnung (nach comeau und GCC) sagt nun, dass die zweite Vorlage mehr spezialisiert ist. Aber warum?

Lassen Sie mich gehen durch partielle Ordnung und zeigen, wo ich Fragen haben. Q kann eine einzigartige hergerichtete Art zur Bestimmung der partiellen Ordnung verwendet werden nach 14.5.5.2.

  • Transformed Parameter-Liste für T1 (Q eingefügt): (Q, typename Const<Q>::type*). Die Typen der Argumente sind AT = (Q, void*)
  • Transformed Parameter-Liste für T2 (Q eingefügt): BT = (Q, void*), die auch die Typen der Argumente.
  • Nicht transformierte Parameterliste für T1: (T, typename Const<T>::type*)
  • Nicht transformierte Parameterliste für T2: (T, void*)

Da C ++ 03 dieses Unter gibt, habe ich die Absicht verwenden, die ich in mehreren Fehlerberichte lesen. Die oben transformierte Parameterliste für T1 (AT von mir genannt) für 14.8.2.1 als Argumentliste verwendet „Ableiten Vorlage Argumente aus einem Funktionsaufruf“ .

14.8.2.1 braucht nicht AT zu verwandeln oder sich BT mehr (wie Referenz Deklaratoren Entfernung, etc.), und geht direkt auf 14.8.2.4 die unabhängig für jeden A / P Paar Abzug nicht geben:

  • AT gegen T2: { (Q, T) , (void*, void*) } . T ist die einzige Template-Parameter hier, und es wird, dass T finden müssen Q werden. Typ Abzug gelingt trivialer für AT gegen T2.

  • BT gegen T1: { (Q, T) , (void*, typename Const<T>::type*) } . Es wird feststellen, dass T Q ist auch hier. typename Const<T>::type* ist ein un-abgeleitete Kontext, und so wird es nicht verwendet werden, um alles abzuleiten.


Hier ist meine erste Frage: Wird diese nun den Wert von T für den ersten Parameter abgeleitet verwenden? Wenn die Antwort nein ist, dann ist die erste Vorlage spezialisierte. Dies kann nicht der Fall sein, weil beide GCC und Comeau sagen, dass die zweite Vorlage speziellere ist, und ich glaube nicht, dass sie falsch sind. Also nehmen wir an „Ja“, und setzen Sie void* in T. Der Absatz (14.8.2.4) sagt „Abzug unabhängig für jedes Paar durchgeführt wird, und die Ergebnisse werden dann kombiniert“ und auch "In bestimmten Kontexten jedoch der Wert nicht in Typ Abzug teilnehmen, aber stattdessen verwendet die Werte von Template-Argumente, die entweder wurden an anderer Stelle oder explizit angegeben abgeleitet. " Das klingt wie‚ja‘zu.

Der Abzug gelingt es daher auch für jedes A / P-Paar. Nun ist jede Schablone mindestens so groß wie die andere spezialisiert, weil Abzug nicht auch auf all impliziten Konvertierungen verlassen hat und in beiden Richtungen gelungen. Als Ergebnis soll der Anruf nicht eindeutig sein.

So ist meine zweite Frage: Nun, warum sagen die Implementierungen, dass die zweite Vorlage speziellere ist? Welche Punkt habe ich übersehen?


Bearbeiten : Ich testete explizite Spezialisierung und Instanziierung und beide in den letzten GCC-Versionen (4.4) sagen Sie mir, dass der Verweis auf dieSpezialisierung ist nicht eindeutig, während eine ältere Version von GCC (4.1) nicht, dass die Mehrdeutigkeit Fehler steigen. Dies deutet darauf hin, dass die jüngsten GCC-Versionen inkonsequent partielle Ordnung für Funktionsschablonen haben.

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*)'
War es hilfreich?

Lösung

Hier ist mein gehen das an. Ich stimme mit Charles Bailey , dass die falschen Schritt von Const<Q>::Type* zu void* gehen

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

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

Die Schritte, die wir nehmen wollen, sind:

14.5.5.2/2

  

zwei überladene Funktionsschablonen gegeben, ob eine speziellere ist als ein anderer durch die Umwandlung jede Vorlage wiederum bestimmt werden kann und mit Argument Abzug (14.8.2), um es dem anderen zu vergleichen.

14.5.5.2/3-b1

  

Für jede Art Template-Parameter, synthetisiert eine einzigartige Art und Ersatz, dass für jedes Auftreten dieses Parameters in der Funktion Parameterliste oder für eine Vorlage Konvertierungsfunktion, in dem Rückgabetyp.

Meiner Meinung nach sind die Typen synthetisiert wie folgt:

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

Ich sehe keine Formulierung, dass der zweite synthetisierte Parameter von T1 erfordert, dass void* werden. Ich weiß nicht, jeder Präzedenzfall für die entweder in einem anderen Kontext. Der Typ Const<Q>::Type* ist absolut gültige Typ innerhalb des C ++ Typ-Systems.

So, jetzt führen wir die Deduktionsschritte:

Q2 T1

Wir versuchen, die Template-Parameter für T1 abzuleiten, so haben wir:

  • Parameter 1: T wird abgeleitet Q
  • werden
  • Parameter 2: Nondeduced Kontext

Auch wenn Parameter 2 ist ein nicht abgeleitete Zusammenhang Abzug ist es gelungen, nach wie vor, weil wir einen Wert für T haben.

Q1 bis T2

Ableiten der Template-Parameter für T2 haben wir:

  • Parameter 1: T wird abgeleitet Q
  • werden
  • Parameter 2: void* entspricht nicht Const<Q>::Type* so Abzug Ausfall
  • .

IMHO, ist hier, wo der Standard uns im Stich lässt. Der Parameter ist nicht abhängig, so dass es nicht wirklich klar ist, was passieren soll, aber meine Erfahrung (basierend auf einem zusammengekniffenen Lesen von 14.8.2.1/3) besteht darin, dass selbst dann, wenn die Parameter-Typ P nicht abhängig ist, wird der Typ A Argument übereinstimmen sollte es.

Die synthetisierten Argumente von T1 T2 kann verwendet werden, zu spezialisieren, aber nicht umgekehrt. T2 ist daher spezialisierter als T1 und so ist die beste Funktion.


UPDATE 1:

Just deckt das poing über Const<Q>::type nichtig ist. Betrachten Sie das folgende Beispiel:

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);
}

In der oben Const<int>::type wird verwendet, wenn wir die übliche Überladungsauflösung Regeln Leistung erbringt, aber nicht, wenn wir zu der Teil Überlastung Regeln bekommen. Es wäre nicht richtig sein, eine beliebige Spezialisierung für Const<Q>::type zu wählen. Es kann nicht intuitiv sein, aber der Compiler ist sehr glücklich, eine synthasized Art der Form Const<Q>::type* zu haben und es bei dem Typ Abzug zu verwenden.


UPDATE 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);
}

Wenn die Const Vorlage mit einem gewissen Wert I instanziert wird, es instanziiert selbst rekursiv bis I 0 erreicht Dies ist, wenn die partielle Spezialisierung Const<T,0> ausgewählt ist. Wenn wir einen Compiler haben, die für die Parameter der Funktion einige echte Art synthetisiert, dann welchen Wert wird der Compiler für den Array-Index wählen? Sagen 10? Nun, das wäre gut für das obige Beispiel, aber es würde die partielle Spezialisierung Const<T, 10 + 1> nicht überein, die vom Konzept her zumindest in einer unendlichen Anzahl von rekursiven instantiations der primären führen würden. Was auch immer Wert, dass es ausgewählt konnten wir die Endbedingung modifizieren, dass Wert + 1, zu sein, und dann würden wir eine Endlosschleife im Teilordnungsalgorithmus haben.

Ich sehe nicht, wie die partielle Ordnung Algorithmus korrekt Const instanziiert könnte wha findent type wirklich ist.

Andere Tipps

Edit: Nach dem Studium der Clang der Implementierung (von Doug Gregor) ihrem Teilordnungsalgorithmus, ich bin gekommen, um stimmen mit dem Rest der Plakate, die das ursprüngliche Beispiel nicht ‚bestimmt‘ zu sein, nicht eindeutig - auch wenn der Standard nicht so klar ist, wie es sein, was in solchen Situationen passieren sollte. Ich habe diesen Beitrag bearbeitet meine Gedanken überarbeitet, um anzuzeigen (für meinen eigenen Nutzen & Referenz). Insbesondere geklärt Clang-Algorithmus, dass ‚typename Const<T>::type‘ wird nicht in die ‚Leere‘ während der partiellen Ordnung Schritt -. Und dass jeder A / P-Paar unabhängig voneinander abgeleitet

Am Anfang habe ich mich gefragt, warum wurde die folgende Wortlaut als zweideutig:

        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.)

aber folgende wäre nicht zweideutig:

        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

(Der Grund, warum man es nicht eindeutig sein, erwarten könnte, ist, wenn folgendes geschehen sollte:
 - 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*)
Wenn das wahr wäre, würde weder eine spezialisierte mehr als die andere.)

Nach Clang partiellem Ordnungsalgorithmus Studium ist es klar, dass sie über ‚3‘ zu behandeln, als wäre es:

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

so Abzug von einigen einzigartigen 'U' gegen 'Typnamen X :: type' wird erfolgreich sein -

  • 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)

Und so '2' ist deutlich stärker spezialisiert als '3'.

  

Transformed Parameterliste für T1 (Q   eingefügt): (Q, typename   Konst :: type *). Die Arten der   Argumente sind AT = (Q, void *)

Ich frage mich, ob das wirklich eine richtige Vereinfachung ist. Wenn Sie den Typ Q synthetisieren, sind Sie eine Spezialisierung für Const für die Zwecke der Bestimmung der Reihenfolge der Vorlage specliazation heraufbeschwören erlaubt?

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

Diese, T2 bedeuten würden, nicht mindestens so groß wie T1 spezialisiert, weil ein void* Parameter nicht T1 zweiten Parameter für beliebigen Template-Parameter entspricht.

Edit: Bitte diesen Beitrag ignorieren - Nach clangs Algorithmus für partielle Ordnung Studium als umgesetzt von Doug Gregor (auch wenn es nur teilweise zum Zeitpunkt des Schreibens implementiert ist - es scheint, dass die Logik, die auf den OP Frage relevant ist ausreichend genug umgesetzt wird ) - es scheint, als ob es den undeduced Kontext als nur ein weiteres Template-Parameter behandelt. Daraus lässt sich schließen, dass die Überlastung mit der ausdrücklichen void * Argument sollte die speziellere Version sein und sollte es keine Zweideutigkeit. Wie üblich ist Comeau richtig. Nun, wie für die Formulierung in der Norm, die eindeutig dieses Verhalten definiert - das ist eine andere Sache ...

Da dieser Beitrag auch auf comp.lang.c gepostet ++ moderiert, und scheint es auch einige Verwirrung zu verursachen -. Ich dachte, ich meine Antwort auf diese Gruppe auch hier posten würde - da sich die Diskussion auf die offensichtlich relevant ist Frage gestellt hier.

  

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.

Ich glaube, das ist falsch. Bei der Überprüfung, um zu sehen, welche Funktion mehr spezialisiert (bei Teilbestellung), wandelt der Compiler die Parameter-Liste zu (Q, void*) - das heißt, es instanziiert tatsächlich die relevanten Vorlage (bestes Matching) und sieht darin für den Wert von ‚Typ‘ - in diesem Fall basierte auf der primären Vorlage, wird es void * sein.

In Bezug auf Ihren Punkt über Teil-Spezialisierung - bei der Überprüfung für welche Vorlage ist spezialisierter als die andere, die einzige Art, die verwendet werden kann, erzeugte Typ ist der einzigartige - wenn es andere Spezialisierungen an dem Punkt, die Instanziierung der Erklärung (wenn die Überladungsauflösung wird durchgeführt) sie werden in Betracht gezogen werden. Wenn Sie sie später hinzufügen, und sie sollten ausgewählt bekommen Sie ODR verstoßen wird (nach 14.7.4.1)

Die Teil / explizite Spezialisierungen werden auch erhalten considertaion während Bildung des Kandidatensatzes - aber diesmal die Typen der tatsächlichen Argumente an die Funktion. Wenn die am besten passende Teil-Spezialisierung (X) ergibt ein Funktionstyp, die eine besseren implizite Konvertierungssequenz für einen Teil hat Parameter, dann nie wir auf die Teilordnungsphase machen, und dass „Besser“ Funktion erhält ausgewählt (bevor es zu dem Teil machen Bestellphase)

Hier ist ein Beispiel mit Kommentaren über das, was sollte bei verschiedenen Schritten los werden:

    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             

    }

Es ist auch erwähnenswert, dass, wenn die primäre Vorlage keine Definition hat - dann SFINAE während der partiellen Ordnung Phase arbeitet, weder von der anderen abgeleitet werden, und Zweideutigkeit sollte zur Folge haben.

Auch wenn Sie eine andere Vorlage hinzufügen, wenn der Punkt von instantation der eine dieser beiden Funktionen zu einem anderen Spiel führen würde an anderer Stelle in der Übersetzungseinheit bewegt wird man deutlich die ODR verletzt.

  

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

     

Als erstes speziellere zu sein, bedeutet, dass diese weniger Typen, bei denen   diese Vorlage kann durch Überladungsauflösung gewählt werden.   Mit diesem können die Regeln für die partielle Ordnung wie folgt zusammengefasst werden: Versuchen Sie,   einen Typ für A, so dass A aber B nicht aufgerufen werden kann, oder Überlastung   Auflösung bevorzugt A. anrufen Wenn dieser Typ gefunden werden kann, dann B ist mehr   spezialisiert als A.

hier kein Argument. Aber auf der Grundlage der Regeln, wie sie derzeit sind, bietet die OP Beispiel sein zweideutig.


Schließlich sind hier explizit, eindeutige Antworten auf die beiden spezifischen Fragen litb erhöht:

1) Wird dieser nun den Wert von T für den ersten Parameter abgeleitet verwenden?
Ja - natürlich hat es, es Template-Argument Abzug tut - die 'Links' müssen eingehalten werden.

2) Nun, warum die Implementierungen sagen, dass der zweite mehr spezialisiert statt?
Denn sie sind falsch;)

Ich hoffe, dass dies das Problem bringt Ruhe - Bitte lassen Sie mich know, wenn es alles, was noch unklar ist:)

Edit: litb hob einen guten Punkt in seinem Kommentar - vielleicht die besagen, dass die primäre Vorlage immer erhalten für die Instanziierung mit dem einzigartigen erzeugten Typ verwendet wird, ist eine zu starke Aussage.
Es gibt Fälle, in denen die primäre Vorlage wird nicht aufgerufen werden.
Was ich bin immer ist, dass, wenn partielle Ordnung auftritt ist, einige einzigartige erzeugt Typ ist verwendet, um die beste Spezialisierung anzupassen. Du hast recht, es muss nicht die primäre Vorlage sein. Ich habe die oben Sprache bearbeitet, dies zu tun. Er hob auch ein Problem in Bezug auf eine bessere Abstimmung Vorlage nach dem Punkt der instantation definieren. Das wird eine Verletzung der ODR sein nach dem Abschnitt über Punkt Instanziierung.


  

Die Norm sagt, dass, wenn die A / P-Paare erzeugt werden (die Regeln der Transformation wie in temp.func.order beschrieben) sie gegeneinander Abzug unter Verwendung von Template-Argument abgeleitet werden (temp.deduct) - und dieser Abschnitt Griffe der Fall von nicht-abgeleitete Kontexte, die Vorlage und seine verschachtelten Typ instanziiert wird, Triggerpunkte instantiations. Der temp.point Abschnitt behandelt die ODR Verletzungen (die Bedeutung der partiellen Ordnung sollte nicht unabhängig von den Punkten der instantation innerhalb einer Übersetzungseinheit ändern). Ich bin noch nicht sicher, wo die Verwirrung herkommt? - Faisal Vali vor 1 Stunde [löschen Kommentar]

     

litb: „Beachten Sie, dass der Schritt, der Q in Konst :: Typ legt die Argumente zu bauen ist nicht explizit von der SFINAE Regel abgedeckt.   Die SFINAE Regeln arbeiten mit dem Argument Abzug, die Absätze setzen, dass Q in die Funktion Template-Funktion Parameterliste setzen sind bei 14.5.5.2. "

Die SFINAE Regeln verwendet hier werden müssen - wie könnten sie nicht sein? Ich fühle es ausreichend angedeutet wird - ich will nicht leugnen, dass es klarer sein könnte, und während ich den Ausschuß ermutigen zu klären das. - Ich glaube nicht, es muss geklärt wird Ihr Beispiel ausreichend zu interpretieren

Lassen Sie mich einen Weg, um sie zu verbinden. Aus (14.8.2): „Wenn eine explizite Template-Argumentliste angegeben ist, muss die Vorlage Argumente mit der kompatibel sein Template Parameterliste und muss in einem gültigen Funktionstyp führen, wie unten beschrieben; ansonsten Typ Abzug versagt "

Von (14.5.5.2/3) „Die Transformation verwendet wird: - Für jede Art Template-Parameter, synthetisiert eine einzigartige Art und Ersatz, dass für jedes Auftreten dass Parameter in der Parameterliste einer Funktion oder für eine Vorlage Konvertierungsfunktion, in dem Rückgabetyp. "

In meinem Kopf, bedeutet das obige Zitat, dass, sobald Sie „schaffen“ einzigartig generierten Typen für jede Template-Parameter, die Funktionsdeklaration sein muss implicity instanziiert von explizit die einzigartigen Typen als Vorlage Argument für unsere Funktionsvorlage zu liefern. Wenn dies führt zu einem ungültigen Funktionstyp, dann nicht nur die Transformation, aber noch wichtiger ist die anschließende Vorlage Argument Abzug erforderlich teilweise um die Funktion fehlschlägt.

Von (14.5.5.2/4) „Mit der Funktion Parameterliste transformierte Argument Abzug gegen die andere Funktionsvorlage durchführt. Die transformierten Vorlage ist mindestens so groß wie der andere spezialisierte , wenn und nur wenn , gelingt es dem Abzug und die abgeleiteten Parametertypen ist eine exakte Übereinstimmung (so wird der Abzug nicht auf implizite Konvertierungen verlassen). "

Wenn die transformierte Funktion Parameterliste führt Versagen zur Substitution, dann wissen wir Abzug nicht gelungen sein könnte. Und da Abzug nicht erfolgreich war, ist es nicht so spezialisiert wie die anderen - das ist alles, was wir wissen müssen, um fortzufahren in teilweise Ordnung der beiden.

  

litb: Ich bin auch nicht sicher, was in diesem Fall passiert: 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); sicher,   das ist indended gültige Code zu sein, aber eine :: Art zu tun, wird es scheitern, weil bei der   Template-Definition Kontext, A ist noch nicht definiert"   Beachten Sie auch, dass es keine POI ist definiert für eine Vorlage instantiations daraus resultierenden   Art der Substitution bei dem Versuch, eine Ordnung (partielle Ordnung zu bestimmen, nicht davon ab,   auf jedem Kontext. Es ist eine statische Eigenschaft von zwei Funktionsschablonen beteiligt).   Ich denke, das im Standard wie ein Problem aussieht, die behoben werden muss.

Ok - ich glaube, ich sehe, wo wir die Dinge anders sehen. Wenn ich Sie richtig verstehe, sind Sie sagen, dass da diese Funktionsschablonen erklärt bekommen, wird der Compiler eine Spur der partiellen Ordnung unter ihnen zu halten, unabhängig von der Überladungsauflösung immer zwischen ihnen wählen immer ausgelöst. Wenn das ist, wie man es interpretieren, dann kann ich sehen, warum Sie das oben beschriebene Verhalten erwarten Sie beschreiben. Aber ich glaube nicht, dass der Standard immer erfordert oder schreibt vor, dass.

Nun ist der Standard klar, dass die partielle Ordnung auf den Typ Agnostiker ist, die in dem Aufruf der Funktion verwendet wird (ich glaube, das ist, was Sie sich beziehen, wenn Sie es als eine statische Eigenschaft beschreiben und es ist kontextunabhängig).

Der Standard ist auch klar, dass es sich nur um partielle Ordnung kümmert sich (ruft teilweise Ordnung) zwischen Funktionsschablonen während des Prozesses der Überladungsauflösung (13.3.3 / 1), wenn und nur wenn es nicht könnte die bessere Funktion wählen, basierend auf ICS oder wenn man eine Schablone und der andere nicht. [Teil Ordnung der Klassenvorlage Teil Spezialisierungen ist ein anderes Thema und in meinem Kopf verwendet den relevanten Kontext (andere Template-Definitionen), die die Instanziierung dieser bestimmten Klasse erfordert.]

So, meiner Meinung nach, da die Maschinerie der partiellen Ordnung von Funktionsschablonen aufgerufen wird, wenn eine Überlastung Auflösung durchgeführt wird, hat es einen relevanten Teil des Kontexts zu verwenden (Templat Definitionen und Spezialisierungen) verfügbar an dem Punkt, wenn die Überladungsauflösung getan wird.

So basiert auf meiner interepretation, nach Ihrem Beispiel ‚template struct A‘ unter Verwendung der oben ist der Code gültig. Die partielle Ordnung ist überhaupt nicht der Definition Kontext getan. Aber wenn / wenn Sie passieren Überlastung Auflösung aufzurufen zwischen den beiden Funktionen durch einen Aufruf f Schreiben ((int *) 0,0) - und zu diesem Zeitpunkt, wenn der Compiler entweder versucht, eine Kandidat Erklärung zu montieren oder sie teilweise zu bestellen (wenn es auf den Teilordnungsschritt wird) Wenn ein ungültigen Ausdruck oder Typ Ergebnisse als Teil des Funktionstypen, hilft SFINAE mir und erzählt wir, dass Vorlage Abzug versagt (soweit teilweise Ordnung betrifft, das bedeutet, dass man nicht mehr spezialisiert als die anderen können, wenn wir die Vorlage nicht einmal verwandeln konnte).

Nun in Bezug auf POIs - wenn Sie überzeugt sind, wie ich bin, dass die transformierten Funktionstypen sollen repräsentieren implizite Instanziierungen explizit gelieferten Template Argumentlisten (unter Verwendung der eindeutig generierten Typen) unter Verwendung von dann sind die folgenden Standard Anführungszeichen relevant:

14.6.4.1/1 Für eine Funktion Vorlage Spezialisierung, eine Member-Funktion Vorlage Spezialisierung oder eine Spezialisierung für ein Memberfunktion oder statische Daten Mitglied einer Klasse Vorlage, wenn die Spezialisierung wird implizit instanziiert weil es aus einer anderen Vorlage Spezialisierung und Kontext verwiesen, aus dem sie verwiesen wird auf einem Template-Parametern abhängig ist, ist der Punkt der Instanziierung der Spezialisierung der Punkt der Instanziierung die umschließenden Spezialisierung.

So wie ich dies zu interpretieren ist, dass die POI des transformierten Funktionstypen und der origianl Funktionstyp ist die gleiche wie die POI für diese Funktionen durch den tatsächlichen Funktionsaufruf erstellt.

  

litb: Da partielle Ordnung ist vielmehr nur   a property of the syntactic form of parameters (i.e "T*" against "T(*)[N]"),   Ich würde stimmen die Spezifikation für die Änderung (wie „wenn Q erscheint in einem verschachtelten Namen Spezifizierers   ein qualifizierter-ID einen Typen zu nennen, dann gestattete der Typ „Q“)   Oder sagt, dass die genannte Art ist ein weiterer einzigartiger typ.   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.   Ich würde darüber nachdenken und einige Testfälle zu machen, um zu sehen, ob diese natürliche Ordnungen ergeben würde, wenn.

Aah - jetzt sind Sie was auf eine mögliche Lösung, die die Mehrdeutigkeit zugunsten dessen, was wir löst erwarten, dass alle intuitiv - das ist ein anderes Problem, und während Ich mag die Richtung, die Sie in zusteuern, wie du, würde ich einige Gedanken in sie gesetzt haben, bevor ihre Verarbeitbarkeit zu verkünden.

Vielen Dank für das Gespräch fortzusetzen. Ich wünschte, so nicht nur Sie Kommentare zu platzieren begrenzen.

Da Sie meine Beiträge editieren, können Sie sich innerhalb der Post zu reagieren, wenn das einfacher ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top