对象集的排序不正确

beg*_*ner 0 c++ overloading object set c++11

当我打印整个集合时,结果是未排序的并且它包含一个副本.该对象Person有姓氏,姓氏和出生年份(所有3个都是字符串).我首先按出生年份排序,然后按姓氏,然后按姓氏排序.本身没有相同的人(但即使是这样,也应该在插入时将其删除set).

更具体一点,我创建了一组这样的人:

std::set <Person> greatUncles; 
Run Code Online (Sandbox Code Playgroud)

并插入它们像这样:

greatUncles.insert(Person("bla", "bla", "1900"));
Run Code Online (Sandbox Code Playgroud)

这是课堂上必不可少的东西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;
}
Run Code Online (Sandbox Code Playgroud)

这是我如何打印这些伟大的叔叔:

void printGreatUncles(std::set <Person> &greatUncles) {
    std::ofstream outputFile;
    outputFile.open("greatuncle.dat");

    if (outputFile.is_open()) {
      for(Person const & person:greatUncles) {
        outputFile << person;
      }
      outputFile.close();
    }
  }
Run Code Online (Sandbox Code Playgroud)

现在,某种情况下的输出应该如下所示(按年份排序):

Sebastian Furtweger 1942
Nikolaus Furtweger 1951
Archibald Furtweger 1967
Run Code Online (Sandbox Code Playgroud)

但它看起来像这样:

Archibald Furtweger 1967
Sebastian Furtweger 1942
Nikolaus Furtweger 1951
Archibald Furtweger 1967
Run Code Online (Sandbox Code Playgroud)

我无法想象我的生活中有什么(事情)我做错了.

Nat*_*ica 6

std::set要求比较器提供严格的弱排序.部分原因是如果a < b == true那样,b < a == false但你没有这个.让我们想象一下,出生年份和姓氏是相同的,只有姓氏是不同的.在你例子中,你将返回其转化为一些正数或负数true,因为只有0false.如果向后运行检查,那么在整数中得到相反的值,但它仍然会产生true.

要解决这个C++ 11提供的问题std::tie,您可以使用它来构建std::tuple成员,并且它operator <是为了做正确的事情而构建的.这使你的代码看起来像

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());
}
Run Code Online (Sandbox Code Playgroud)

如果你想要继续这样做并且可以使用C++ 20,那么你可以添加到Person

auto operator<=>(const Person&) const = default;
Run Code Online (Sandbox Code Playgroud)

并且这将自动为您提供运营商==,!=,<,<=,>和> = for Person,只要您希望所有成员按照他们在班级中定义的顺序进行比较,他们就会"做正确的事情" .