Подтвердить что ты не робот

Как избежать создания привязки для доступа к карте?

У меня есть следующая проблема:

std::map<A*,double> map;

void getColor(A const * obj){
    double d = map[obj]; // does not compile wihtout const_cast<A*>(obj)
    // do something
}

У меня есть карта std::map (где-то), которая хранит указатели на объекты A. У меня есть функция getColor, которая не выполняет манипулирует объектами A и поэтому принимает указатель на ввод const A.

Функция getColor не будет компилироваться без использования const_cast.

Конструкция const - это проблема дизайна, но я не знаю, как обойти ее, если я не хочу делать ключи в map const.

Любая помощь была оценена.

4b9b3361

Ответ 1

Здесь возможны два возможных сценария:

  • Функция знает/ожидает, что obj уже присутствует на карте, и вы используете [] для удобства.

  • Вы используете [] для своего полного потенциала, т.е. вы ожидаете, что он добавит obj к карте, если он еще не существует.

В ситуации 2 у вас есть ошибка в подписи getColor. Так как он может передать obj в место, где он будет сохранен как A*, это значит, что он принимает только const A*. Обратите внимание, что даже если функция не изменяет сам объект, а передает его где-нибудь, где она может быть изменена, она эффективно модифицирует ее косвенно и поэтому должна принимать ее как const.

В ситуации 1 это зависит от вашей версии на С++. В С++ 14 была введена перегрузка шаблона find и связанные с ней функции-члены std::map, которая берет что-то сравнимое с Key вместо только Key. Поэтому вы можете изменить функцию следующим образом:

void getColor( A const * obj){
    doubel d = map.find(obj)->second;
    // do something
}

Обратите внимание, что для этого вам также необходимо изменить тип карты для использования прозрачного компаратора: std::map<A*,double, std::less<>> map; (как впервые указано @Leon answer).

Если вы застряли с С++ 11 или ранее, вам не повезло, и вам придется жить с const_cast. Обратите внимание, что с подходящим комментарием a const_cast является совершенно безопасным и приемлемым в этом случае (не говоря уже о единственном способе продолжения без изменения типа map). Опять же, вы должны использовать find или, возможно, at вместо [], так как вы не хотите вставлять их в карту.

Ответ 2

Если вы можете позволить перейти на С++ 14, вы можете настроить свою карту на использование прозрачного компаратора (это будет работать, поскольку указатель const можно сравнить с указатель не const):

std::map<A*,double, std::less<>> map;
//                  ^^^^^^^^^^^
//                  enable transparent comparator on this map

void getColor( A const * obj){
    auto it = map.find(obj);
    assert(it != map.end());
    double d = it->second;
    // do something
}

Обратите внимание, что вам нужно будет использовать std::map::find() вместо std::map::operator[], поскольку последняя не имеет прозрачной версии.