Этот код демонстрирует проблему, которую я пытаюсь решить:
#include <map>
class Point
{
public:
float m_x;
float m_y;
};
typedef std::set<Point *> PointSet;
typedef std::set<const Point * const> ConstPointSet;
float GetMinimumRange(const ConstPointSet &pointSet)
{
float minimumRange(0.0f);
// find the smallest distance between any pair of points in the set
return minimumRange;
}
float GetMinimumRangeWrong(const PointSet &pointSet)
{
PointSet::iterator first(pointSet.begin());
Point * point(*first);
point->m_x = 42.0f; // I want to prevent this
return 0.0f;
}
class PointSet_
{
public:
std::set<Point *> m_pointSet;
float GetMinumumRange() const
{
PointSet::iterator first(m_pointSet.begin());
Point * point(*first);
point->m_x = 42.0f; // I want to prevent this
return 0.0f;
}
};
void test()
{
PointSet myPointSet;
// Add some points to my set
// This fails because the compiler states it can't convert from PointSet to ConstPointSet.
//float minimumRange1(GetMinimumRange(myPointSet));
// reinterpret_cast<> is the only cast that works here, const_cast fails with the same
// complaint as the line above generates
ConstPointSet *myConstPointSet(reinterpret_cast<ConstPointSet *>(&myPointSet));
float minimumRange1(GetMinimumRange(*myConstPointSet));
float minimumRange2(GetMinimumRangeWrong(myPointSet));
}
Я хочу создать подпрограмму, которая принимает PointSet
, оценивает минимальный диапазон между любой парой Point
в наборе, но гарантирует, что она вообще не изменит переданное ей PointSet
. Он не может изменять элементы любого указанного Point
, не может изменять сами указатели, а также не может добавлять или удалять элементы из набора.
Проблема в том, что компилятор правильно рассматривает PointSet
и ConstPointSet
как разные типы из-за разницы в квалификаторах const
внутреннего типа и поэтому отказывается выполнять приведение между ними, хотя я добавляю только квалификаторы const
.
Я попытался создать класс, содержащий PointSet
, и создать функцию-член const, но даже там он позволяет модифицировать один из внутренних Point
. По крайней мере, MSVC скомпилирует это без жалоб. Признаюсь, я был весьма удивлен этим.
Единственный способ, который я нашел, это использовать reinterpret_cast<>
для преобразования указателя на PointSet
в указатель на ConstPointSet
. Стандарт отмечает, что reinterpret_cast<>
можно использовать для добавления квалификаторов const
, но применимо ли это в данном случае?
Если нет, есть ли способ сделать то, что я хочу? Я понимаю, что хорошая дисциплина кода может быть использована для гарантии того, что GetMinimumRange()
не изменяет переданный PointSet
, но я хотел бы получить эти квалификаторы const
по двум причинам.
Они гарантируют, что если кто-либо когда-либо изменит
GetMinimumRange()
, они не смогут изменитьPointSet
.Это позволит компилятору оптимизировать вызов
GetMinimumRange()
. При отсутствии квалификаторовconst
на вызывающем сайте нельзя делать никаких предположений относительно значений, которые могут кэшироваться во время вызова, что может привести к избыточной выборке данных.
set<T>
иset<U>
, которые не имеют отношения, если толькоT
иU
не идентичны. - person M.M   schedule 20.02.2015Point *
на самом деле являются указателями на Entites в игре. Использование набора‹› из них, а не набора указателей, будет иметь некоторые очевидные проблемы с производительностью. - person dgnuff   schedule 20.02.2015ConstPointSet
, находится в прототипеGetMinimumRange()
, и оно там по причинам, указанным в нижней части моего исходного сообщения. Если я создаю шаблонGetMinimumRange()
, я мог бы также удалитьConstPointSet
, что оставляет меня в ситуации, когда у меня есть подпрограмма, которая хочет принятьPointSet
, но также гарантирует, что она никоим образом не изменит ее. Учитывая проблему с псевдонимами, кажется, что для этого нет решения. - person dgnuff   schedule 20.02.2015PointSet::iterator first(pointSet.begin());
компилируется. Разве функция-членbegin()
не должна возвращать здесь const_iterator? - person MikeMB   schedule 20.02.2015Point * point(*first);
, а не наpoint->m_x = 42;
, если вы хотите, чтобы здесь была ошибка - person M.M   schedule 20.02.2015const Point * point(*first);
Я, конечно, могу написать это, если захочу, но меня не заставляют это делать. - person dgnuff   schedule 20.02.2015set::iterator
иset::const_iterator
- это одно и то же. Вот почему он компилируется. - person Michael Karcher   schedule 20.02.2015const_iterator
. Однако потом я узнал, что std::set::const_iterator и std::set::iterator на самом деле могут быть одного и того же типа, так как оба в любом случае указывают на константный элемент. Чтобы относиться к вашему вопросу: если количество элементов невелико, вероятно, было бы жизнеспособным решением скопировать указатели изstd::set<Point *>
вstd::set<Point const*>
перед передачей их функции - person MikeMB   schedule 20.02.2015std::vector<>
,std::list<>
и т. д. Учитывая, что эти наборы строятся по одному на игровой сеанс, я мог бы даже использовать простойPoint **
, выделенный черезnew[]
, мне не нужно делатьfind()
наstd::set<>
в реальный мир, поэтому порядок не важен, мне просто нужно перебрать все члены. - person dgnuff   schedule 20.02.2015std::set<>
менялось. - person dgnuff   schedule 20.02.2015static_cast
. - person T.C.   schedule 20.02.2015qualifier_ptr
или сделайте константные копии указателей. - person MikeMB   schedule 20.02.2015typedef std::set<const Point * const>
не помещайте туда вторую константу. - person Neil Kirk   schedule 20.02.2015Object
, на которые указывает его список‹› что является полной противоположностью того, что я хочу - person dgnuff   schedule 01.03.2015const
является тривиальной и очевидной модификацией решения. - person Ben Voigt   schedule 01.03.2015set<MyClass *>
и преобразовать его вconst set<MyClass *>
тривиально, и это разрешено спецификацией, просто добавьте ключевое словоconst
. Это то, что Миро хочет сделать. Вместо этого я хочу преобразоватьset<MyClass *>
вset<const MyClass *>
, что явно не разрешено. Если один случай явно разрешен спецификацией, а другой явно запрещен, как они могут быть одной и той же проблемой? - person dgnuff   schedule 01.03.2015