Вставка объектов в вектор с использованием lower_bound со структурой сравнения

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

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, я получаю много ошибок, в том числе:

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

ты уверен, что хочешь string msg быть const? Это означает, что его нельзя изменить после инициализации, и именно это мешает вам его вставить.

Stack Danny 10.04.2019 14:05

Спасибо за все ответы, теперь я понимаю проблему. Однако я не могу изменить class Mail в том числе const string msg. Я изменил вектор на вектор указателей vector<CMail*>.

Infinittty 10.04.2019 15:08
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
73
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Deleted implicitly-declared copy assignment operator

A defaulted copy assignment operator for class Tis 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 Tis defined as deleted if any of the following is true:

  • T has a non-static data member that is const;
Ответ принят как подходящий

Ошибки в 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.

Сноски:

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

Другие вопросы по теме