This code demonstrates the problem I'm trying to solve:
#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));
}
I want to create a routine that takes a PointSet
, evaluates the minimum range between any pair of Point
s in the set, but that it guarantees that it won't modify the PointSet
passed to it in any way at all. It can't modify the members of any referenced Point
, it can't change the pointers themselves, nor can it add or remove members from the set
The issue is that the compiler correctly views PointSet
and ConstPointSet
as different types because of the difference of const
qualifiers of the inner type, and therefore refuses to cast between them, even though I'm only adding const
qualifiers.
I tried creating a class to contain a PointSet
, and creating a const member function, but even in there it allows modification to one of the inner Point
s. At least MSVC will compile that without complaint. I'll confess I was quite surprised about this.
The only way I've found that works is to use a reinterpret_cast<>
to convert a pointer to a PointSet
to a pointer to a ConstPointSet
. The standard does note that reinterpret_cast<>
can be used to add const
qualifiers, but does that apply in this case?
If not, is there any way to do what I want? I realize that good code discipline can be used to ensure that GetMinimumRange()
doesn't modify the passed PointSet
, but I'd like to get those const
qualifiers in there for two reasons.
They will ensure that if anyone ever modifies
GetMinimumRange()
they can't cause it to modify thePointSet
.It will allow the compiler to optimize over the call to
GetMinimumRange()
. In the absence of theconst
qualifiers, no assumptions can be made at the calling site regarding values that could be cached across the call, thus possibly leading to redundant fetches of data.