Вставка объектов в вектор с использованием lower_bound со структурой сравнения - PullRequest
2 голосов
/ 10 апреля 2019

У меня есть этот класс:

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;
  }
};

Я хочу иметь вектор с объектами Mail, отсортированными по их сообщению const string msg.Однако, когда я пытаюсь вставить новый объект в вектор, используя lower_bound, я получаю много ошибок, в том числе:

передача строки const, поскольку аргумент this игнорирует квалификаторы.

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.
Извините, если об этом уже спрашивали, ноЯ не нашел ответа на эту проблему.

Ответы [ 2 ]

0 голосов
/ 10 апреля 2019

Ошибки в C ++ иногда трудно диагностировать. Мой совет - всегда начинать сверху и сначала разрешать. В этом случае есть длинный список из них , но все они на самом деле об одном и том же - оператор присваивания для Mail не может быть сгенерирован.

Подумайте об этом так, компилятор помогает и пытается сгенерировать (и внутри lower_bound(), использовать) эту функцию:

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

Но это невозможно, потому что это присвоение в теле недопустимо из-за того, что msg является const. Вы также не можете написать это самостоятельно, так как вы также не можете назначить переменную const.

Обычно вам не нужно, чтобы переменные-члены были const, потому что они становятся const, если сам экземпляр класса 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 член, вы не можете использовать операторы присваивания с классом. Это перерывы.

Удалите это 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 .

Сноска

  • Вы можете использовать лямбду для comaparator, чтобы избежать шаблонов вокруг класса 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(), если вы знаете, сколько предметов вы поместите в свой вектор.
0 голосов
/ 10 апреля 2019

Проблемы здесь относятся к оператору назначения удаленной копии и оператору назначения удаленного перемещения из-за члена const string msg; в классе Mail:

Удален неявно объявленный оператор присвоения копии

Оператор присваивания по умолчанию для класса T определяется как удаленный , если выполняется любое из следующих условий:

  • T имеет нестатический член данных не-классового типа (или его массив), равный const;

Удален неявно объявленный оператор присваивания перемещения

Неявно объявленный или не заданный по умолчанию оператор присваивания перемещения для класса T определяется как удаленный , если выполняется любое из следующих условий:

  • T имеет нестатический элемент данных, равный const;
...