2010-03-23 24 views
10

Nếu tôi có một lớp mà tôi muốn có thể sắp xếp (tức là hỗ trợ khái niệm ít hơn), và nó có một số mục dữ liệu như tôi cần phải làm theo thứ tự từ điển, tôi cần một cái gì đó như sau:Cách đơn giản nhất để xác định so sánh lexicographic cho các thành phần của một lớp là gì?

struct MyData { 
    string surname; 
    string forename; 

    bool operator<(const MyData& other) const { 
    return surname < other.surname || (surname==other.surname && forename < other.forename); } 
}; 

Điều này trở nên khá không thể quản lý được với bất kỳ điều gì có hơn 2 thành viên dữ liệu. Có cách nào đơn giản hơn để đạt được nó? Các thành viên dữ liệu có thể là bất kỳ lớp so sánh nào.

Trả lời

4

Với sự ra đời của C++ 11 có một cách mới và súc tích để đạt được điều này bằng std::tie:

bool operator<(const MyData& other) const { 
    return std::tie(surname, forename) < std::tie(other.surname, other.forename); 
} 
2

Bạn có thể sử dụng số boost::tuple hoặc std::pair có so sánh từ vựng được tích hợp sẵn. Tất nhiên bất lợi là bạn không thể kết hợp một phương thức với các bộ dữ liệu.

5

Bạn có thể lưu trữ dữ liệu trong một boost::tuple, cung cấp so sánh tự từ điển, và cung cấp các chức năng accessor đặt tên, dọc theo dòng:

#include <boost/tuple/tuple.hpp> 
#include <boost/tuple/tuple_comparison.hpp> 

struct Data { 
    string &surname() {return stuff.get<0>();} 
    string &forename() {return stuff.get<1>();} 

    // it would be polite to add const overloads too. 

    bool operator<(const Data &other) const {return stuff < other.stuff;} 

private: 
    boost::tuple<string, string> stuff; 
}; 

Tôi tin rằng điều này cũng có sẵn như là std::tr1::tuple, và sẽ std::tuple trong tiêu chuẩn sắp tới.

Việc duy trì danh sách người truy cập có thể dễ quản lý hơn việc duy trì mã so sánh.

+1

giải pháp thú vị. Có vẻ như một sự xấu hổ để mất các lĩnh vực được đặt tên mặc dù như nhìn thấy nội dung của lớp trong trình gỡ lỗi trở nên khó khăn hơn. –

+4

Bạn có thể giữ các trường được đặt tên và chỉ sử dụng bộ tuple cho mục đích so sánh, ví dụ: 'return boost :: tie (tên họ, tên) UncleBens

+2

Thậm chí tốt hơn, quấn' tie' trong một hàm thành viên. Sau đó, bạn chỉ phải duy trì một danh sách duy nhất của thứ tự từ điển. –

3

Nếu tất cả thành viên có cùng loại bạn có thể đặt chúng trong std::vector. Theo mặc định, std::lexicographical_compare sẽ được sử dụng để so sánh vectơ.

9

tuple là một ý tưởng tốt, nhưng nếu bạn muốn giữ lại có tên cho các biến thành viên của bạn, nó có thể là tốt, đủ để tái cơ cấu chức năng so sánh của bạn như thế này:

struct MyData { 
    string surname; 
    string forename; 
    string var; 
    // ... 

    bool operator<(const MyData& other) const { 
     if (surname != other.surname) return surname < other.surname; 
     if (forename != other.forename) return forename < other.forename; 
     if (var != other.var) return var < other.var; 

     // ... 

     return false; //< They are equal 
    } 
}; 

Tùy thuộc vào khẩu vị của bạn, có lẽ bạn thậm chí muốn có macro như #define COMPARE(field) if (field != other.field) return field < other.field; để giảm trùng lặp. Sau đó, hàm sẽ chỉ trở thành một danh sách của COMPARE -invocations.

+0

Có thể '#define LEX_LT (mem) nếu (mem! = Other.mem) trả về mem kennytm

+0

Tôi thích cách bố trí của nó, nó dễ quản lý hơn và ít bị lỗi hơn so với lồng nhau-if. Tôi không chống lại việc sử dụng macro không thường xuyên, và điều đó có thể thuận tiện cho các cấu trúc lớn hơn, nhưng tôi nghĩ rằng hình thức cơ bản là đủ rõ ràng. –

Các vấn đề liên quan