使用 lower_bound 和比较结构将对象插入向量

Inserting objects into vector using lower_bound with compare struct

我有这个class:

class Mail {
  public:
    Mail(const string & msg) : msg(msg) {}

    const string msg;
};

以及比较两个 Mail 对象的结构:

struct Compare {
  bool operator()(const Mail & mail, Mail const & mail2) const {
    return mail.msg < mail2.msg;
  }
};

我想要一个向量,其中包含按消息排序的邮件对象 const string msg。但是,当我尝试使用 lower_bound 将新对象插入到向量中时,出现许多错误,包括:

passing ‘const string as ‘this’ argument discards qualifiers.

int main() {
  vector <Mail> mails;

  Mail mail2("1");
  mails.push_back(mail2);

  const string msg = "2";
  Mail mail(msg);
  auto low = lower_bound(mails.begin(), mails.end(), mail, Compare());

  // mails.push_back(mail);   // OK
  mails.insert(low, mail); // passing ‘const string as ‘this’ argument discards qualifiers

  return 0;
}

我还不太了解 const 的用法,无法弄清楚哪个 const 是错误的。
很抱歉,如果有人问过这个问题,但我还没有找到这个问题的答案。

由于 Mail class 中的 const string msg; 成员,此处的问题与删除的复制赋值运算符和删除的移动赋值运算符有关 class:

Deleted implicitly-declared copy assignment operator

A defaulted copy assignment operator for class T is defined as deleted if any of the following is true:

  • T has a non-static data member of non-class type (or array thereof) that is const;

Deleted implicitly-declared move assignment operator

The implicitly-declared or defaulted move assignment operator for class T is defined as deleted if any of the following is true:

  • T has a non-static data member that is const;

C++ 中的错误有时很难诊断。我的建议是始终从头开始,首先解决那个问题。在这种情况下,有 a long list of them,但它们实际上都是关于同一件事的——无法生成 Mail 的赋值运算符。

这样想,编译器很有帮助,正在尝试生成(并在 lower_bound() 内部使用)这个函数:

Mail& operator=( const& Mail mail ) 
{ 
    msg = mail.msg; 
    return *this;
}

但不能,因为正文中的赋值无效,因为 msgconst。你也不能真正自己写,因为你也不能分配给 const 变量。

通常你不需要成员变量是const,因为如果class的实例本身是const:[=32=,它们就会变成const ]

const auto mail1 = Mail{"1"};
auto       mail2 = Mail{"2"};

mail1.msg = "3"; // FAIL! msg is const since mail1 is const
mail2.msg = "4"; // Ok! msg is not const

如果您确实需要 const 成员,则不能对 class 使用赋值运算符。他们是休息时间。

删除 const 一切正常:

#include <vector>
#include <string>
#include <algorithm>

using namespace std;

class Mail {
  public:
    Mail(const string & msg) : msg(msg) {}

    string msg; //////////////////////////////// Not const!
};

struct Compare {
  bool operator()(const Mail & mail, Mail const & mail2) const {
    return mail.msg < mail2.msg;
  }
};

int main() {
  vector <Mail> mails;

  Mail mail2("1");
  mails.push_back(mail2);

  const string msg = "2";
  Mail mail(msg);
  auto low = lower_bound(mails.begin(), mails.end(), mail, Compare());

  // mails.push_back(mail);   // OK
  mails.insert(low, mail); // OK!

  return 0;
}

Coliru.

上观看 运行

脚注:

  • 您可以对比较器使用 lambda 以避免在 class Compare:
  • 周围出现一些样板
const auto low = lower_bound( begin(mails), end(mails), mail, 
                              []( const auto& mail1, const auto& mail2 ) 
                              { return mail1.msg < mail2.msg; } );
  • 您可以使用 vector::emplace_back() 就地构建项目,避免复制。以下块实际上做同样的事情,但第二个更有效:
const auto mail = Mail{"2"};
mails.push_back( mail2 ); // Copies

mails.emplace_back("2"); // Creates it right in the vector
  • 如果您知道要在向量中放入多少项,请考虑使用 vector::reserve()