Избегание const_cast при вызове std:: set <Type *>:: find
Есть ли хороший способ избежать const_cast
ниже, сохраняя при этом константную корректность?
Без const_cast
приведенный ниже код не компилируется. set::find
получает ссылку const на тип заданного ключа, поэтому в нашем случае он не должен изменять значение указателя переданного; однако ничто не гарантировало, что он не изменит то, на что указывает указатель.
class C {
public:
std::set<int*> m_set;
bool isPtrInSet(const int* ptr) const
{
return m_set.find(const_cast<int*>(ptr)) != m_set.end();
}
};
Ответы
Ответ 1
Да.
В С++ 14 вы можете использовать свой собственный компаратор, который объявляет int const*
прозрачным. Это позволит перегрузка шаблона find()
, которая может сравнивать ключи с произвольными типами. См. Этот связанный вопрос SO. И здесь объяснение Джонатана Вакели.
Ответ 2
Я хочу объяснить основную логику, почему это невозможно.
Предположим, что set<int*>::find(const int*)
будет законным. Затем вы можете сделать следующее:
set<int*> s;
const int* p_const;
// fill s and p
auto it = s.find(p_const);
int* p = *it;
Эй, престо! Вы преобразовали const int*
в int*
без выполнения const_cast
.
Ответ 3
Если вы хотите сохранить const int*
s, сохраните const int*
s. Если вы хотите сохранить int*
вместо этого, сделайте это, но вы не можете смешивать и сопоставлять это (по крайней мере, не без взлома, который вы уже использовали).
Выберите один и придерживайтесь его.
Ответ 4
Есть ли хороший способ избежать const_cast ниже, сохраняя константную корректность?
Я не уверен, что то, что я собираюсь предложить, квалифицируется как "хороший способ". Однако вы можете избежать const_cast
, если вы не возражаете против итерации над содержимым набора самостоятельно. Имейте в виду, что это преобразует то, что может быть операцией O (log (N)) для операции O (N).
bool isPtrInSet(const int* ptr) const
{
for ( auto p : m_set )
{
if ( p == ptr )
{
return true;
}
}
return false;
}