为什么在使用operator()对std :: set进行排序时必须实现operator <

时间:2019-01-10 19:07:40

标签: c++ struct set compare

在代码审查期间,我的一个同事正在使用结构对std :: set进行排序。我还是C ++的新手,必须自己实现它才能完全理解它。可悲的是,我有些挣扎,因为在实现结构的operator()之后,MSVC也迫使我实现operator <。

有人可以解释一下为什么如果我使用结构对std :: set进行排序的话,为什么必须同时实现两个运算符?我猜测不需要operator <,因为std :: set调用了一些基本的比较功能?

class Hallo {
int one;
int two;
public:
Hallo(int one, int two);

bool operator < (const Hallo& rhs) const
{
    return one < rhs.GetOne();
}

struct cmpStruct{
bool operator()(Hallo const &lhs, Hallo const &rhs) const
{
        return lhs.GetOne() < rhs.GetOne();
}

int main(int ac, char* av[]){
const Hallo a{ 1, 1 };
const Hallo b{ 2, 2 };
const Hallo c{ 3, 3 };
const Hallo d{ 5, 5 };

std::set<Hallo, Hallo::cmpStruct> sortedList{};
std::set<Hallo> unsortedList{};

sortedList.insert(b);
sortedList.insert(c);
sortedList.insert(a);
sortedList.insert(d);

unsortedList.insert(b);
unsortedList.insert(c);
unsortedList.insert(a);
unsortedList.insert(d);

3 个答案:

答案 0 :(得分:2)

默认情况下,$enrollment = $user->enrollments() ->where('course_id', $course->id) ->first(); // If $enrollment is NULL, they don't belong to this Course dd($enrollment->completed); 使用std::set比较两个operator <实例。这就是为什么您需要定义一个Hallo函数进行比较的原因。没有用于比较operator<的默认操作。

编辑1:指定排序或比较功能
struct构造函数之一允许您指定一个用于比较std::set实例的函数。如果您不想向结构添加重载的Hallo方法,则需要将比较两个operator<实例的函数传递给Hallo构造函数。同样,std::setstruct实例没有默认的比较运算符;您必须创建一些东西。

编辑2:比较功能的目的
class的比较函数参数允许您为std::set结构指定比较函数。它允许您创建一个按成员Hallo订购的商品,也可以创建另一个按one成员订购的商品。

此外,您可以定义升序或降序的排序功能。选择很丰富。

答案 1 :(得分:2)

  

有人可以解释一下为什么如果我使用结构对std :: set进行排序的话,为什么必须同时使用两个运算符?

因为您创建了两个{"_module": "oauth2client.client", "scopes": ["https://www.googleapis.com/auth/spreadsheets"], "token_expiry": "2019-01-10T20:32:28Z", "id_token": null, "user_agent": "ResponseRates", "access_token": FIRST_STRING_OF_CHARACTERS, "token_uri": "https://accounts.google.com/o/oauth2/token", "invalid": false, "token_response": { "access_token": FIRST_STRING_OF_CHARACTERS, "scope": "https://www.googleapis.com/auth/spreadsheets", "expires_in": 3600, "token_type": "Bearer"}, "client_id": SECOND_STRING_OF_CHARACTERS.apps.googleusercontent.com", "token_info_uri": "https://www.googleapis.com/oauth2/v3/tokeninfo", "client_secret": THIRD_STRING_OF_CHARACTORS, "revoke_uri": "https://accounts.google.com/o/oauth2/revoke", "_class": "OAuth2Credentials", "refresh_token": FOURTH_STRING_OF_CHARACTORS, "id_token_jwt": null } 实例,并以std::set作为键,并且在第一个实例中您明确地将class Hallo用作函子,但是在第二个实例中却隐式地使用了{{1} },如Apples docs on InAppPurchases

中所述
cmpStruct

std::less使用“一些基本比较功能”,即template< class Key, class Compare = std::less<Key>, class Allocator = std::allocator<Key> > class set; this discussion

  

用于执行比较的功能对象。除非专门,否则会在类型T上调用操作符<< / strong>。

重点是我的。因此,除非您将std::less专用于operator<或不将std::less实例化中的class Hallo替换为其他内容,否则将需要std::less作为方法或独立函数。 / p>

答案 2 :(得分:0)

任何数学集合的成员都是唯一的;没有两个可以拥有相同的密钥。但是,对于struct这样的用户定义类型,相同是什么意思?我们知道两个字符串相等或两个整数意味着什么。但是,对您的结构而言,“相同”的含义取决于您,也取决于您定义。

std::set的成员根据定义既是唯一的又是排序的。因此,除了强制唯一性之外,std::set依次表示成员。什么顺序?同样,对于用户定义的类型,由用户决定一个对象“小于”另一个对象的含义。

这就是operator<出现的地方。您定义一个对象小于另一个对象的含义。 std::set以用户定义的类型调用用户定义的运算符,并按定义的顺序放置成员。它还使用该函数来实现唯一性:如果无法在现有项之前或之后插入新项,则该新项等于该项,并且拒绝插入。