2009-07-22 6 views
8

Ich habe den folgenden Code (sorry für den großen Code Brocken, aber ich konnte es nicht mehr einengen)mehrdeutig Vorlage Seltsamkeit

template <bool B> 
struct enable_if_c { 
     typedef void type; 
}; 

template <> 
struct enable_if_c<false> {}; 

template <class Cond> 
struct enable_if : public enable_if_c<Cond::value> {}; 

template <typename X> 
struct Base { enum { value = 1 }; }; 

template <typename X, typename Y=Base<X>, typename Z=void> 
struct Foo; 

template <typename X> 
struct Foo<X, Base<X>, void> { enum { value = 0 }; }; 

template <typename X, typename Y> 
struct Foo<X, Y, typename enable_if<Y>::type > { enum { value = 1 }; }; 

int main(int, char**) { 
     Foo<int> foo; 
} 

aber es funktioniert nicht mit gcc (v4.3) mit

kompilieren
foo.cc: In function ‘int main(int, char**)’: 
foo.cc:33: error: ambiguous class template instantiation for ‘struct Foo<int, Base<int>, void>’ 
foo.cc:24: error: candidates are: struct Foo<X, Base<X>, void> 
foo.cc:27: error:     struct Foo<X, Y, typename enable_if<Y>::type> 
foo.cc:33: error: aggregate ‘Foo<int, Base<int>, void> foo’ has incomplete type and cannot be defined 

OK, so ist es mehrdeutig. aber ich habe nicht erwartet, dass es ein Problem ist, da es bei der Spezialisierung fast immer eine Zweideutigkeit geben wird. Dieser Fehler wird jedoch nur ausgelöst, wenn die Klasse mit enable_if<...> verwendet wird, wenn ich sie durch eine Klasse wie die folgende ersetze, gibt es kein Problem.

template <typename X, typename Y> 
struct Foo<X, Y, void > { enum { value = 2 }; }; 

Warum verursacht diese Klasse keine Zweideutigkeit, während die anderen dies tun? Sind die beiden nicht dasselbe für Klassen mit einem wahren :: Wert? Wie auch immer, irgendwelche Hinweise darauf, was ich falsch mache, werden geschätzt.

Danke für die Antworten, mein eigentliches Problem (der Compiler, um meine erste Spezialisierung wählen) wurde durch Ersetzen struct Foo<X, Base<X>, void> mit struct Foo<X, Base<X>, typename enable_if< Base<X> >::type > gelöst, die die Art, wie ich will zu arbeiten scheint.

+0

Der Markdown-Editor ist nicht wysiwyg in Bezug auf

+0

Ich reparierte es zuvor, überschrieb meine Änderungen :) Wenn Sie möchten, können Sie zu meiner Ausgabe zurückkehren (Ich habe die Schaltfläche "10101", die automatisch das Zeug als Code markiert, sollten Sie verwenden dieser Knopf auch). –

+0

Uhjm ... Ich habe es wieder getan, ohne Ihren Kommentar zu lesen litb –

Antwort

12

Der Kern Ihrer Frage ist, dass Sie haben:

template <typename X, typename Y, typename Z> 
struct Foo {}; 

template <typename X> 
struct Foo<X, Base<X>, void> {};     // #1 

template <typename X, typename Y> 
struct Foo<X, Y, typename whatever<Y>::type> {}; // #2 

und Sie versuchen, passen sie

Foo<int, Base<int>, void> 

Offensichtlich beide Spezialisierungen Spiel (die erste mit X = int, der zweite mit X = int, Y = Base<int>).

Gemäß dem Standard, Abschnitt 14.5.4, wird, wenn es mehrere übereinstimmende Spezialisierungen gibt, eine partielle Ordnung (wie in 14.5.5.2 definiert) unter ihnen konstruiert und die am meisten spezialisierte wird verwendet. In Ihrem Fall ist keiner jedoch spezialisierter als der andere. (Einfach gesagt, eine Vorlage ist spezialisierter als eine andere, wenn Sie jeden Typ-Parameter der letzteren Vorlage durch einen Typ ersetzen können und im Ergebnis erhalten Sie die Signatur des ehemaligen. Wenn Sie whatever<Y>::type haben und Sie ersetzen Y durch Base<X> erhalten Sie whatever<Base<X> >::type nicht void, dh es gibt keine Verarbeitung durchgeführt wird.)

Wenn Sie #2 mit

template <typename X, typename Y> 
struct Foo<X, Y, void > {};      // #3 

dann der Kandidat beide Vorlagen enthält wieder eingestellt ersetzen, aber # 1 ist speziellere dann solche # 3 und als ist ausgewählt.

+0

das beantwortet meine Frage, aber mein Kernproblem bleibt. Ich weiß nicht, wie Folgefragen hier gemacht werden sollen, aber ich werde einfach einen Kommentar versuchen. gibt es eine Möglichkeit zu bekommen, was ich will, um # 1 ausgewählt werden, wenn "Foo " instansiating? wie den Compiler zu täuschen, um zu denken, dass # 1 vielleicht mehr spezialisiert ist. – keis

+0

+1, wobei a +10 wäre besser geeignet. Es hat so lange gedauert, die Antwort zu schreiben, dass Sie mich schlagen * nur * 29 Minuten :) –

+2

@keis: Das Problem ist, dass Spezialisierung eine Teilaufgabe ist, und in einigen Fällen sind zwei Elemente wirklich nicht geordnet. Nun, wenn Sie angeben, was Sie wirklich erreichen wollen (schreiben Sie eine Vorlage, die, wenn sie mit int instanziiert wird, einen Wert von 1 hat, während wenn sie mit X einen Wert von 2 hat), dann können Sie bessere Hinweise erhalten –

-1

sind nicht Sie ein Symbol

< 

fehlt?

+0

< and > ging zum HTML-Parser der Seite verloren, hoffe ich habe es jetzt behoben. – keis

-2

Ich glaube, Sie vermissen ein ‚<‘, sollte eine Vorlage wie folgt aussehen:

template< typename T > 
struct myStruct 
{}; 

//OR 

template< class T > 
struct myStruct 
{}; 
+0

Oh, du hast den Code repariert, diese Antwort ist jetzt überflüssig. – DeusAduro

+0

Warum würdest du mich runtermelden? Ich habe geantwortet, bevor der Code bearbeitet wurde. An diesem Punkt machte meine Antwort Sinn ... – DeusAduro

+1

Weil es keinen Sinn ergibt * jetzt *. Wenn Sie die neue Frage nicht bearbeiten möchten, löschen Sie Ihre Antwort vollständig. – avakar