2010-06-09 5 views
13

У меня есть класс с несколькими числовыми полями, такими как:Реализация оператора <в C++

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

мне нужно использовать объекты этого класса в качестве ключа в std::map. Поэтому я реализую operator<. Какова самая простая реализация operator< для использования здесь?

EDIT: Значение < можно считать таким образом, чтобы гарантировать уникальность тех пор, пока какой-либо из полей не равны.

EDIT 2:

Упрощенная реализация:

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; 
} 

Вся причина этого поста только что я обнаружил, что выше реализация слишком многословным. Там должно быть что-то более простое.

+0

Вы должны сначала решить, что «<» означает, что для случая, когда несколько членов представляют инвариант класса. –

ответ

4

Это зависит от того, является ли заказ важным для вас в любом случае. Если нет, то вы можете просто сделать это:

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

Спасибо! Это то, что я искал. –

+0

Или, для удовольствия, 'return a! = Other.a? A Skizz

+8

Я не вижу, каким образом это лучше, чем «упрощенная реализация», которую дал ОП. Эта версия менее читаема. – Frank

28

Я предполагаю, что вы хотите реализовать лексикографическое упорядочение.

#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

Ницца! Но усиление слишком тяжело для моего конкретного случая. –

+0

Отлично, никогда не думал об использовании кортежей! –

+1

@Agnel Kurian: не нужно «использовать» его дальше, чем этот галстук. Это тоже заголовок, чтобы минимизировать влияние сборки (время/зависимости), вы можете выделить его в отдельный блок компиляции (но для создания релизов подумайте о том, чтобы сделать это в заголовке для inline!) – sehe

-4

Вы можете сделать:

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

но не имеет достаточно много предостережений - не VTBL, например, и много больше, я уверен.

+4

Это почти никогда не будет работать должным образом. –

+0

@Peter: OP только хочет «гарантировать уникальность, если любое из полей неравномерно», поэтому добавление offsetof для получения адреса первого ключевого поля и обеспечение того, что ключевые поля смежны, memcmp должен делать трюк , – Skizz

15

Я думаю, что есть непонимание того, что map требует.

map не требует, чтобы ваш класс имел operator<. Для этого требуется подходящий предикат сравнения, который по умолчанию равен std::less<Key>, который использует operator< на Key.

Вы не должны использовать operator<, чтобы поместить свой ключ в map. Вы должны реализовать его только в том случае, если вы определяете его для этого класса: то есть, если он имеет смысл.

Вы вполне могли бы определить предикат:

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

А потом:

typedef std::map<Key,Value,Compare> my_map_t; 
Смежные вопросы