【问题标题】:What is the intution behind std::set<Key,Compare,Allocator>::find() function using the '<' operator instead of '==' operator?使用 '<' 运算符而不是 '==' 运算符的 std::set<Key,Compare,Allocator>::find() 函数背后的直觉是什么?
【发布时间】:2020-04-17 09:45:33
【问题描述】:

为什么一组自定义类(比如说 Person)上的 find() 函数调用不等式运算符 '&lt;' 而不是 '==' 。为了说明,我有以下代码,我在一组 Person 类上调用 find 函数(请参阅 test2())。 .

#include<iostream>
#include<stdio.h>
#include<string>
#include<set>
using namespace std ; 

class Person {
friend ostream & operator<<(ostream &os  , const Person p) ;

string name ; 
int age;
public : 

    Person()
:name{"Unknown"}, age{0}{
    }
    Person(string name , int age )
        :name{name}, age{age}
        {
            }
    //OVERLOADED operators 
    bool operator<(const Person &rhs) const;
    bool operator ==(const Person &rhs) const;
};

bool Person::operator<(const Person &rhs) const{
    cout<<" < operator called"<<endl;
    return this->age < rhs.age;
}

bool Person::operator==(const Person &rhs)  const{
    cout<<"Equality operator"<<endl;
    return (this->age == rhs.age && this->name == rhs.name);
}

ostream & operator<<( ostream &os , const Person p ){
    os<<p.name <<":"<<p.age<<endl;
    return os;
}

template<class T>
void display(const set<T> &s1){
    for (const auto &temp : s1){
        cout<<temp <<" ";
    }
    cout<<endl;
}

void test2(){
        cout<<"====================TEST2=========="<<endl;
    set<Person> stooges {
        {"Larry",2},
        {"Moe",1},
        {"Curly",3},
    };
    cout<<"Something random "<<endl;
    auto it = stooges.find(Person{"Moe",1});   //Calls the '<' operator
}

int main(){
test2();
    return 0;
}

我还在重载运算符 '&lt;' 和 '==' 的定义中编写了 cout 语句。 输出内容为:

====================TEST2==========
 < operator called
 < operator called
 < operator called
 < operator called
 < operator called
Something random 
 < operator called
 < operator called
 < operator called
Hit any key to continue...

【问题讨论】:

  • 要求是可以对集合中键的元素进行排序,即通过根据某些标准比较它们以某种顺序一致地放置。如果唯一的比较方法是==,则不可能这样做。考虑一个包含三个键的集合,"A""B""C""A" == "B""A" == "C""B" == "C" 的比较都将比较为 false - 这根本没有提供有关如何将它们排序为任何顺序的信息。而比较 "A" &lt; "B""A" &lt; "C""B" &lt; "C" 确实提供了有关如何订购它们的信息。
  • 除了排序之外,请注意,等价是比等价更弱的条件,并且要求定义等价将是不必要的限制。

标签: c++ stl c++14


【解决方案1】:

因为std::find 使用等价而不是等价。等价使用operator&lt;判断两个对象ab是否相同:

!(a < b) && !(b < a) 

如果a不小于bb不小于a,那么它们是等价的。

【讨论】:

  • 在 OP 的情况下,这也意味着集合中每个年龄不能有超过一个 Person。所以std::set&lt;Person&gt; s{{"Larry", 3}, {"Moe", 3}}; 的大小是 1 而不是 2(因为 &lt; 不使用名称,只使用年龄)即使 !(Person{"Larry", 3} == Person{"Moe", 3})。这是完全合法的,但这是不直观的行为,应该避免,因为它很容易产生错误。
  • @n314159:虽然这可以通过将name 合并到比较中来解决,以提供总排序。在现代 C++ 中也很容易高效地实现,这要归功于 std::tie 提供了一种执行字典排序的零拷贝方式:只需将 operator&lt; 返回替换为 return std::tie(age, name) &lt; std::tie(rhs.age, rhs.name);。或者您只是记录该类仅适用于std::multiset,而不是std::set,因此两个年龄相同的人的等价性并不妨碍您存储两者。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-16
  • 1970-01-01
  • 2020-10-09
  • 1970-01-01
  • 2011-04-18
  • 1970-01-01
相关资源
最近更新 更多