2010-03-06 8 views
15

Zum Beispiel, wenn ich habe:Kann ich Operatoren für Aufzählungstypen in C++ überladen?

typedef enum { year, month, day } field_type; 

inline foo operator *(field_type t,int x) 
{ 
    return foo(f,x); 
} 
inline foo operator -(field_type t) 
{ 
    return t*-1; 
} 
int operator /(distance const &d,field_type v) 
{ 
    return d.in(v); 
} 

Denn wenn ich es eigentlich legal nicht solche Operatoren definieren ist day*3 zu schreiben und es würde in 6 übersetzt werden?

So ist es legal?

Zumindest gcc und Intel Compiler akzeptieren dies ohne eine Warnung.

clearification:

Ich möchte nicht, Standardrechenoperationen, möchte ich meine eigenen Operationen, die nicht-Integer-Typ zurück.

+0

Was ist das 'foo' Typ? – AnT

+0

foo ist eine komplexe Datenstruktur zum Beispiel 'struct foo {field_type type, int value; } ' – Artyom

Antwort

7

Ja, eine Überladung des Operators kann für Enum- und Klassentypen durchgeführt werden. Die Art und Weise Sie es tun, ist in Ordnung, aber Sie sollten + verwenden, um die Auszählung zu fördern, statt *-1 oder etwas (das Ziel ist letztlich eine unendliche Rekursion, weil -t zu vermeiden):

inline foo operator -(field_type t) { 
    return -+t; 
} 

Dies auch auf andere Operationen skaliert . + wird die Aufzählung auf einen Integer-Typ heraufstufen, der seinen Wert darstellen kann, und Sie können - anwenden, ohne eine unendliche Rekursion zu verursachen.


Beachten Sie, dass Ihre operator* nur Sie erlaubt enum_type * integer zu tun, aber nicht umgekehrt. Es kann sich lohnen, auch die andere Richtung zu betrachten.

Beachten Sie auch, dass es immer ein bisschen gefährlich ist, Operatoren für Operanden zu überladen, die von eingebauten Operatoren bereits akzeptiert werden (wenn auch nur durch implizite Konvertierungen). Stellen Sie sich vor, dass distance eine Umwandlung Konstruktor Mitnahmen int hat (wie in distance(int)), dann gegeben operator/ folgendes ist mehrdeutig

// ambiguous: operator/(int, int) (built-in) or 
//   operator/(distance const&, field_type) ? 
31/month; 

Dazu vielleicht ist es besser, field_type eine echte Klasse mit den entsprechenden Betreiber zu machen, so dass Sie kann solche impliziten Konvertierungen von vornherein ausschließen. Eine andere gute Lösung wird durch C++ 0x's enum class bereitgestellt, die starke Aufzählungen bereitstellt.

+0

Danke, es war wirklich hilfreich, ich wollte nur sicher sein, dass ich nicht etwas mache, das nicht wirklich gut definiert ist. – Artyom

-1

Ja, es ist legal. ENUM wird automatisch Werte in INT verwandeln.

+0

das ist genau ich will nicht. Ich frage, ist es legal zu überladen? – Artyom

+0

@Artyom: Falsch. Sie haben ausdrücklich gefragt: "Wenn ich ** solche Operatoren nicht definiere, ist es eigentlich legal," Tag * 3 "zu schreiben und es würde in" 6 "übersetzt?". Dies ist offensichtlich die Antwort auf diese Frage. – AnT

1

Wenn Sie fragen, ist dieser Code legal:

enum A { 
    x,y 
}; 

int main() { 
    int z = x * y; 
} 

Die Antwort ist leider "ja". Es gibt eine implizite Umwandlung von Enum-Werten in Ganzzahlen.

0

Nun, die Antwort auf Ihre Frage über day * 3 ist: Ja, Sie können es tun. Sie brauchen dafür keinen Operator zu überladen. Und das Ergebnis wird 6 sein. Dies wird jedoch funktionieren, indem Sie Ihre day-Konstante in einen int-Typ umwandeln, eine Multiplikation innerhalb des int-Typs durchführen und das Ergebnis vom Typ int geben, d.h. dass 6 ein int ist. Was die nächste Frage aufwirft: Geht es Ihnen gut, dass es ein int ist?Was planen Sie danach mit diesem 6? Wenn ein int für Ihren Zweck in Ordnung ist, müssen Sie nichts tun.

Es ist jedoch möglich, dass Sie tatsächlich das Ergebnis field_type Typ von day * 3 erhalten möchten. Sie sehen, in C++ int Typ ist nicht explizit in Enum-Typen konvertierbar. So wird dies kompilieren und

int product = day * 3; 

arbeiten, aber das wird nicht

field_type product = day * 3; // ERROR 

Sie können die letztere zwingen, indem Sie eine explizite Umwandlung

field_type product = (field_type) (day * 3); 

oder Sie starten mit Operator spielen kann zu kompilieren Überlastung, wie

field_type operator *(field_type lhs, int rhs) 
{ 
    return (field_type) ((int) lhs * rhs) 
} 

Beachten Sie, dass die Implementierung des überladenen Operators immer noch auf einem Cast basiert. Dies ist also nur eine Möglichkeit, den "Haupt" -Code Ihres Programms sauberer zu machen, indem die hässlichen Umwandlungen in dedizierte Operatoren gekapselt werden (nichts ist falsch).

Als eine pedantische Randbemerkung möchte ich hinzufügen, dass es gewisse formelle Gefahren gibt, wenn man versucht, die Ergebnisse ganzzahliger arithmetischer Operationen in einen Enum-Typ zu pressen (wenn Sie das wollen, vielleicht nicht Sie scheinen einen anderen Typ foo für das Ergebnis zu verwenden, das keine Details darüber liefert). Der Wertebereich, den ein Enumerationsobjekt darstellen kann, wird [grob] durch den maximalen Wert (Betrag) der Enum-Konstante bestimmt, die auf die nächsthöhere (nach Größe) Zahl der Form 2^N-1 gerundet wird. In Ihrem Fall ist der höchste Wert day gleich 2, was bedeutet, dass Ihre enum garantiert Werte bis zu 3 genau darstellt. Wenn Sie versuchen, 6 in Ihren Enum-Typ zu konvertieren, ist das Ergebnis nicht angegeben (obwohl es normalerweise "wie erwartet" in der Praxis funktioniert).

+0

"Da Sie scheinen, mit einem anderen Typ foo" tatsächlich habe ich nur nicht erwähnt, es ist nur eine einfache Klasse, die sowohl Enum und Off-Set halten, so dass ich schreiben kann Datum + = Jahr * 3 + Monat * 3 + Woche Typ würde die vollen Offsets halten. – Artyom

+0

Ihre 'operator *' - Implementierung endet in endloser Rekursion –

+0

@Johannes: Sie haben Recht. Fest. – AnT

Verwandte Themen