operatore <confronto di più campi

Ho il seguente operatore <che dovrebbe essere ordinato prima da un valore, poi da un altro valore:

inline bool operator < (const obj& a, const obj& b) { if(a.field1< b.field1) return true; else return a.field2 < b.field2; } 

Ho la sensazione che questo non sia corretto e che non puoi farlo senza un altro terzo test di confronto sulle variabili dei membri, ma non riesco a trovare alcun esempio in cui ciò non funzioni. Quindi, questo dovrebbe davvero essere come previsto? Grazie

modifica: l’avrei codificato come:

  inline bool operator < (const obj& a, const obj& b) { if(a.field1 b.field1) return false; else return a.field2 < b.field2; } 

ci sono delle differenze? Te lo chiedo perché so che il mio è corretto per esperienza ma anche più lungo del primo

Mi piacerebbe fare tutto da solo ..

Dovresti solo confrontare i valori di Obj::field2 se i valori di Obj::field1 sono uguali.

Il modo facile da capire:

 /* This will meet the requirements of Strict-Weak-Ordering */ if (a.field1 != b.field1) return a.field1 < b.field1; else return a.field2 < b.field2; 

Il modo corretto (consigliato):

Il modo " corretto " di implementarlo utilizza solo l' operator< per confrontare i campi, il sotto sembra più complicato di quanto non sia in realtà.

Risulterà comunque lo stesso risultato dell'esempio di facile comprensione precedentemente scritto.

 return a.field1 < b.field1 || ( !(b.field1 < a.field1) && a.field2 < b.field2 ); 

Ci deve essere un modo per implementare l' operator< senza causare un sacco di mal di testa?

C ++ 11

Puoi usare std::tuple dall'STL che ha già l' operator< per più campi definiti, come nell'esempio seguente.

 #include  ... inline bool operator< (Obj const& lhs, Obj const& rhs) { return std::tie (lhs.field1, lhs.field2) < std::tie (rhs.field1, rhs.field); } 

C ++ 03

Se il tuo compilatore non ha ancora il supporto per C ++ 11 e hai solo bisogno di confrontare due campi da ciascun object, potresti usare std::pair .

Il motivo per std::make_pair è lo stesso dell'esempio precedente usando std::tie .

 #include  ... inline bool operator< (Obj const& lhs, Obj const& rhs) { return std::make_pair (lhs.field1, lhs.field2) < std::make_pair (rhs.field1, rhs.field2); } 

usando std::pair sarà necessario creare copie dei membri da creare, che in alcune circostanze non è desiderabile.

Questa pratica è davvero raccomandata?

Vedere la domanda / risposte di seguito per ulteriori informazioni, ma per riassumere; l'approccio c ++ 11 non causa così tanto overhead ed è molto semplice da implementare.

  • Implementare operatori di comparazione tramite 'tuple' e 'tie', una buona idea?

Pensa a cosa succede se a.field1 è maggiore di b.field1 ma a.field2 è minore di b.field2 . In tale circostanza, si confronta in base esclusivamente a field2 che non è ciò che si desidera.

Devi solo mettere in campo field2 in cui i campi field1 sono uguali, quindi quello che stai cercando è qualcosa di simile (pseudo-codice):

 if a.field1 < b.field1: return true if a.field1 > b.field1: return false # field1s is equal here. return a.field2 < b.field2 

No. Devi anche prendere (a.field1 > b.field1) .

Questo non è un rigoroso ordinamento debole, perché darebbe (1,2) < (2,1) , ma anche (2,1) < (1,2) .

Ecco una versione che si basa sulla logica di cortocircuito per evitare la ramificazione esplicita

 template bool operator< (T const& a, T const& b) { return ( ( a.field1 < b.field1 ) || (( a.field1 == b.field1 ) && ( a.field2 < b.field2 )) ); } 

Ciò presuppone che il tuo tipo primitivo di field1 abbia un operator== . Diventa noioso scrivere questo per più di 2 campi, ma potresti usare std::lexicographical_compare se la tua class obj memorizza i campi all'interno di uno std::array per alcuni tipi T e taglia N

 template struct obj { std::array field; }; bool operator< (obj const& a, T const& b) { return std::lexicographical_compare( a.field.begin(), a.field.end(), b.field.begin(), b.field.end() ); } 

Si noti che esiste una bozza di documento N3326 che discute l'aggiunta di operatori == e < automaticamente per i tipi di class.