2012-11-24 20 views
5

Es tut mir leid, das klingt wie eine allgemeine Frage, ich konnte die Antwort auf mein Problem nicht finden, soweit ich sah. Der nächste Beitrag wäre dieser: Template Specialization for basic POD onlyTyp Konflikt in Vorlage Operator Überladung

Sagen wir, ich habe eine Klasse template <class T> class A {...};, und ich möchte Operator + als interne Binäroperators zu überlasten (zwei Objekte vom Typ A), und als gemischter Binäroperators (Objekt des Typs A und numerischer POD-Typ).

Idealerweise was würde Ich mag schreiben ist:

#include <type_traits> 
using namespace std; 

// Declare/fine template 
template <class T> class A {...}; 

// Internal binary operator 
template < class T, class U > 
    A< typename common_type<T,U>::type > 
operator+ (const A<T> &a, const A<U> &a) { ... } 

// Mixed binary operator 
template < class T, class U > 
    A< typename common_type<T,U>::type > 
operator+ (const A<T> &a, const U &b) { ... } 

Aber dann scheint es, wie die zweite Definition in Konflikt mit dem ersten ist. Mit der zweiten Definition weiß ich, wie man sicherstellt, dass U ein numerischer POD-Typ ist, das ist nicht der Punkt. Wenn ich so gehe, ist das Problem, dass ich keine Möglichkeit habe zu wissen, welcher zugrundeliegende Schablonentyp in U eingeschlossen ist.

Bitte sagen Sie mir, wenn meine Frage nicht klar genug ist, und danke im Voraus! :)

EDIT: Die Template-Spezifikation wurde durch den HTML-Filter gelöscht, in meinem letzten Satz "U, wenn es einige A<T>" ist. Kurz gesagt, T ist versteckt.

+0

'template ,> U :: Wert, leer> :: type> A :: type> operator + (const A & a, const U &b); 'sollte den Trick machen. – Morwenn

+0

Was meinst du mit" zugrunde liegenden Vorlagentyp in U eingeschlossen? "Der gemischte Operator würde nicht wählen, wenn U' A 'weil das interne ist eine bessere Übereinstimmung.Wollen Sie den Fall 'A < A>' in der internen Operator behandeln? – pmr

+0

Vielen Dank für Ihre Hilfe. pmr, Sie haben Recht, das Problem passiert eigentlich vorher, wegen common_type.So gibt es keine gemeinsame Geben Sie zwischen 'A ' und U, wir ein Bort vor dem besten Spiel kann beurteilt werden. Morwenn, deine Lösung sieht aus wie etwas, das ich versucht habe, ist aber in diesem Zusammenhang falsch; U könnte 'A ' mit S sein!= T, und ich sollte noch in der Lage sein, die Operation durchzuführen. – Sheljohn

Antwort

2

Sie können es mit einem kleinen Helfer Zug machen arbeiten, um Spezialisierungen von A von allgemeineren Typen zu unterscheiden:

#include <type_traits> 


// "A" template  

template <typename> class A {}; 


// Traits for "A-ness": 

template <typename> struct is_a : std::false_type { }; 
template <typename T> struct is_a<A<T>> : std::true_type { }; 


// Operators: 

template <class T, class U> 
A<typename std::common_type<T, U>::type> 
operator+(const A<T> & a, const A<U> & b); 

template <class T, class U, 
      typename = typename std::enable_if<!is_a<U>::value>::type> 
A<typename std::common_type<T, U>::type> 
operator+(const A<T> & a, const U & b); 

Dies sofort die zweite Überlastung vom tragfähige Satz schließt und so das Problem der Rückkehr der Bestimmung Art der zweiten Überlast kommt nie auf, wenn nur der erste gewünscht wird.

(Dies ist ein Beispiel für enable_if in Verzug geratener Vorlage Argumente mit der Überlastung Satz zu steuern.)

+0

Du bist ein Lebensretter :) Ich bin neu in diesen "Template-Programmierung" Tricks, ich denke, das ist genau das, was ich brauche. Lass es mich testen und ich werde die Antwort validieren. Danke noch einmal! – Sheljohn

+0

Es funktioniert, vielen Dank! :) – Sheljohn

1

Sie könnten ein SFINAE freundlich common_type schreiben - ich bin persönlich im Lager, dass Züge sollte fast immer SFINAE . Nämlich:

// Black hole metafunction that eats everything 
template<typename...> struct void_ { using type = void; }; 

template<typename... T> 
using Void = typename void_<T...>::type; 

// Due to std::common_type being variadic we need to 
// pass a variadic pack around 
template<typename... T> struct list {}; 

// Actually defined, but with no member types for SFINAE purposes 
template<typename Sequence, typename Sfinae = void> 
struct common_type_impl {}; 

template<typename... T> 
struct common_type_impl<list<T...>, Void<typename std::common_type<T...>::type>> 
: std::common_type<T...> {}; 

template<typename... T> struct common_type: common_type_impl<list<T...>> {}; 

Nun, wenn es keine gemeinsame Art zwischen A<T> und U die Überlastung wird aus der Liste der Kandidaten statt lärmend beschweren entfernt werden.

Es ist auch möglich, std::common_type vollständig zu ersetzen, da das Ergebnis, das es berechnet, Probleme hat, wie in DR 2141 dokumentiert. Ich werde keinen Ersatz vorstellen, weil nicht klar ist, was eine bessere Lösung ist, insbesondere denke ich, dass der vorgeschlagene Beschluss der DR schlechter ist.

+0

Also nur um sicherzustellen, dass ich richtig verstehe, was hier passiert, weil ich es eigentlich ziemlich schwierig finde; Wenn ich diese neue Version von common_type in meinem Code verwende, sagen wir einmal mit einem definierten common-type, und einmal ohne, wird SFINAE tatsächlich in meinem eigenen Code passieren .. das ist dein Satz "Nun, wenn es kein ... " Recht? Und wenn es für keine der beiden Implementierungen überhaupt einen Common-Type gibt, dann befinden wir uns nicht mehr in einer SFINAE-Situation und erzeugen in diesem Fall einen Kompilierfehler, right (bis)? – Sheljohn

+0

@ Sh3ljohn Ich folge nicht, was Sie mit "einmal mit" meinen - das ist ein Drop-in-Ersatz von "std :: common_type", und ist völlig in Bezug auf es. Wo auch immer Sie 'std :: common_type' verwenden würden, verwenden Sie stattdessen dieses: es tut und bedeutet genau das gleiche, aber führt immer zu einem weichen Fehler anstatt zu einem harten Fehler. Wenn es sich um explizite Spezialisierung handelt, dann gibt es nichts besonderes zu tun - schreibe die explizite Spezialisierung für 'std :: common_type' und dieser wird sie auswählen. –

+0

Ja, ich habe, was es tut. In meinem Fall (siehe Originalquellen) ist es nicht wirklich eine Template-Spezialisierung mehr als eine Template-Überladung von Operator +; "einmal mit" bezog sich auf eine der beiden Erklärungen. Ich möchte nur sicherstellen, dass Ihr Vorschlag zu einem "sich gegenseitig ausschließenden" Verhalten führt, wenn der Operator mit gültigen Typen aufgerufen wird und dass die Übergabe eines Typs 'B ' immer noch zu einem "harten Fehler" führt. – Sheljohn

Verwandte Themen