C++ 对象集的排序不正确
当我打印整个集合时,结果是未排序的,并且它包含一个副本。 对象C++ 对象集的排序不正确,c++,c++11,object,set,overloading,C++,C++11,Object,Set,Overloading,当我打印整个集合时,结果是未排序的,并且它包含一个副本。 对象Person有姓氏、家庭名和出生年份(三个都是字符串)。我先按出生年份排序,然后按家庭名称,再按姓氏排序。就其本身而言,不存在完全相同的人(但即使是这样,在将他们插入集合时也应将其删除) 更具体地说,我创建了一组这样的人: std::set <Person> greatUncles; greatUncles.insert(Person("bla", "bla", "1900")); Archibald Furtweg
Person
有姓氏、家庭名和出生年份(三个都是字符串)。我先按出生年份排序,然后按家庭名称,再按姓氏排序。就其本身而言,不存在完全相同的人(但即使是这样,在将他们插入集合时也应将其删除)
更具体地说,我创建了一组这样的人:
std::set <Person> greatUncles;
greatUncles.insert(Person("bla", "bla", "1900"));
Archibald Furtweger 1967
Sebastian Furtweger 1942
Nikolaus Furtweger 1951
Archibald Furtweger 1967
以下是课堂上的基本内容Person
:
class Person {
public:
//...
Person(std::string s, std::string f, std::string y)
:surname(s), familyname(f), yearOfBirth(y)
{
}
//...
std::string getSurname() const {
return surname;
}
std::string getFamilyname() const {
return familyname;
}
std::string getYearOfBirth() const {
return yearOfBirth;
}
private:
std::string surname;
std::string familyname;
std::string yearOfBirth;
};
//to print the set, overload the '<<' operator
std::ostream &operator<<(std::ostream &o, const Person &person) {
o << person.getSurname() << " "
<< person.getFamilyname() << " "
<< person.getYearOfBirth() << std::endl;
return o;
}
//to order the set, overload the '<' operator
bool operator< (Person const &p1, Person const &p2) {
int compareYearOfBirth = p1.getYearOfBirth().compare(p2.getYearOfBirth());
if (compareYearOfBirth == 0) {
int compareFamilyname = p1.getFamilyname().compare(p2.getFamilyname());
if (compareFamilyname == 0) {
return p1.getSurname().compare(p2.getSurname());
} else
return compareFamilyname;
} else
return compareYearOfBirth;
}
但看起来是这样的:
std::set <Person> greatUncles;
greatUncles.insert(Person("bla", "bla", "1900"));
Archibald Furtweger 1967
Sebastian Furtweger 1942
Nikolaus Furtweger 1951
Archibald Furtweger 1967
我一辈子都想不出我做错了什么。你是在把std::string::compare
返回的int
作为bool
返回。这不是您想要的,因为1
和-1
都转换为true
正确的比较代码为:
//to order the set, overload the '<' operator
bool operator< (Person const &p1, Person const &p2) {
int compareYearOfBirth = p1.getYearOfBirth().compare(p2.getYearOfBirth());
if (compareYearOfBirth == 0) {
int compareFamilyname = p1.getFamilyname().compare(p2.getFamilyname());
if (compareFamilyname == 0) {
return p1.getSurname().compare(p2.getSurname()) < 0;
} else
return compareFamilyname < 0;
} else
return compareYearOfBirth < 0;
}
这将基本上提供所有比较,就像您通过对所有成员的比较手动实现它们一样。std::tie
d一起。std::set
要求比较器提供严格的弱排序。部分原因是如果a
那么b
但是你没有这个。让我们想象一下,出生年份和姓氏是一样的,只是姓氏不同。在您的示例中,您将返回一些正数或负数,这些正数或负数转换为true
,因为只有0
是false
。如果向后运行检查,则整数中会出现相反的值,但结果仍然是true
要修复此问题,C++11提供了std::tie
,可用于构建成员及其运算符的std::tuple
。请不要将…
放在代码段中,或将其放在注释中,这会使您的代码无法直接复制/粘贴/运行。感谢您的反馈,我会记住的。我会认为这是一个惯用的解决方案。1@JesperJuhl至少现在是这样。C++20允许使用doauto操作符(const class\u name&)const=default代码>当然,但这仍然是一个未发布的标准。您发布的是C++17及更低版本的惯用解决方案。:)将方法编写为_tuple
可能会避免重复p1
和p2
的成员@Jarod42如果tie创建了一个引用元组,而不是到_tuple()
来创建一个类似元组的副本,那么将其命名为会更好吗?我这样问是因为我根本没有理由这么做。
bool operator< (Person const &p1, Person const &p2) {
return std::tie(p1.getYearOfBirth(), p1.getFamilyname(), p1.getSurname()) <
std::tie(p2.getYearOfBirth(), p2.getFamilyname(), p2.getSurname());
}
auto operator<=>(const Person&) const = default;