2010-06-09 34 views
13

Ich habe eine Klasse mit einigen numerischen Feldern wie:Implementierung Operator <in C++

class Class1 { 
    int a; 
    int b; 
    int c; 
public: 
    // constructor and so on... 
    bool operator<(const Class1& other) const; 
}; 

Ich brauche Objekte dieser Klasse als Schlüssel in einem std::map zu verwenden. Ich implementiere daher operator<. Was ist die einfachste Implementierung von operator< hier zu verwenden?

EDIT: Die Bedeutung von < davon ausgegangen werden kann, um die Eindeutigkeit zu gewährleisten, solange eines der Felder ungleich sind.

EDIT 2:

Eine vereinfachte Implementierung:

bool Class1::operator<(const Class1& other) const { 
    if(a < other.a) return true; 
    if(a > other.a) return false; 

    if(b < other.b) return true; 
    if(b > other.b) return false; 

    if(c < other.c) return true; 
    if(c > other.c) return false; 

    return false; 
} 

Der ganze Grund für diesen Beitrag ist nur, dass ich die obige Implementierung zu ausführlich gefunden. Es sollte etwas einfacher sein.

+0

Sie müssen zunächst entscheiden, was ‚<‘ bedeutet für den Fall, dass mehrere Mitglieder der Invariante der Klasse darstellen. –

Antwort

4

Es hängt davon ab, ob die Bestellung für Sie in irgendeiner Weise wichtig ist. Wenn nicht, könnten Sie einfach tun:

bool operator<(const Class1& other) const 
{ 
    if(a == other.a) 
    { 
     if(b == other.b) 
     { 
      return c < other.c; 
     } 
     else 
     { 
      return b < other.b; 
     } 
    } 
    else 
    { 
     return a < other.a; 
    } 
} 
+0

Danke !! Das ist, was ich gesucht habe. –

+0

Oder, zum Spaß, 'return a! = Other.a? A Skizz

+8

Ich sehe nicht, auf welche Weise das ist besser als die "simple Implementierung", die das OP gab. Diese Version ist weniger lesbar. – Frank

28

Ich nehme an, Sie möchten lexikographisch bestellen implementieren.

#include <boost/tuple/tuple.hpp> 
#include <boost/tuple/tuple_comparison.hpp> 
bool Class1::operator<(const Class1& other) const 
{ 
    return boost::tie(a, b, c) < boost::tie(other.a, other.b, other.c); 
} 
+0

Schön! Aber Boost ist zu schwer für meinen speziellen Fall. –

+0

Toll, dachte nie an Tupel! –

+1

@Agnel Kurian: keine Notwendigkeit, es weiter als diese eine Krawatte "zu verwenden". Es ist auch Header-Only, um Build-Auswirkungen (Zeit/Abhängigkeiten) zu minimieren, können Sie es in eine separate Kompilierungseinheit isolieren (aber für Release-Builds, ziehen Sie es in die Kopfzeile für Inlining!) – sehe

-4

könnten Sie tun:

return memcmp (this, &other, sizeof *this) < 0; 

aber das hat ziemlich viel von Einsprüche - kein vtbl zum Beispiel und viel mehr bin ich sicher.

+4

Das wird fast nie wie vorgesehen funktionieren. –

+0

@Peter: Das OP will nur die Eindeutigkeit garantieren, solange eines der Felder ungleich ist. Wenn also ein offsetof hinzugefügt wird, um die Adresse des ersten Schlüsselfeldes zu erhalten und sicherzustellen, dass die Schlüsselfelder zusammenhängend sind, sollte memcmp den Trick machen . – Skizz

15

Ich denke, es ist auf ein Missverständnis, was map erfordert.

map erfordert nicht Ihre Klasse operator< definiert haben. Es erfordert, dass ein passendes Vergleichs-Prädikat übergeben wird, das üblicherweise std::less<Key> ist, das operator< auf dem Key verwendet.

Sie sollten operator< nicht implementieren, um Ihren Schlüssel in map zu passen. Sie sollten es nur implementieren, wenn Sie es für diese Klasse definieren: dh wenn es sinnvoll ist.

Sie könnten durchaus ein Prädikat definieren:

struct Compare: std::binary_function<Key,Key,bool> 
{ 
    bool operator()(const Key& lhs, const Key& rhs) const { ... } 
}; 

Und dann:

typedef std::map<Key,Value,Compare> my_map_t; 
Verwandte Themen