I have a class holding a pointer to a container. The container offers access to subsets of its items. This is realized by a method with const and non-const version returning a vector of const/non-const pointers. The following code in a minimal (not fully functional) excerpt from a more complex setup:
#include <vector>
struct Entity
{ int dummy; };
template <typename Value>
struct MyContainer
{
typedef Value* pointer;
typedef Value const* const_pointer;
std::vector<pointer> pointers() {
std::vector<pointer> ret;
return ret;
}
std::vector<const_pointer> pointers() const {
std::vector<const_pointer> ret;
return ret;
}
};
struct MyType
{
typedef MyContainer<Entity> ContainerType;
ContainerType* m_data; // I cannot make this a non-pointer attribute
std::vector<Entity*> pointers() {
std::vector<Entity*> ret = m_data->pointers();
return ret;
}
std::vector<Entity const*> pointers() const {
std::vector<Entity const*> ret = m_data->pointers(); // error!
return ret;
}
// std::vector<Entity*> pointers() const {
// std::vector<Entity*> ret = m_data->pointers();
// return ret;
// }
};
int main() {
MyType obj;
MyType const& constobj = obj;
std::vector<Entity*> pointers = obj.pointers();
std::vector<Entity const*> constpointers = constobj.pointers();
// std::vector<Entity*> constpointers = constobj.pointers();
}
Clang 3.8.0 (also 3.5.2) reports an error:
error: no viable conversion from 'vector<pointer>' to 'vector<const Entity *>'
std::vector<Entity const*> ret = m_data->pointers();
^ ~~~~~~~~~~~~~~~~~~
The commected code compiles fine, however, my intent is to give const access to items obtained through the const access path (via constobj
), hence the const method should return pointers of type Entity const*
. Changing the type of m_data
from ContainerType*
to ContainerType
solves the problem, but that's not an option in my original code.
MyType::pointers() const
calls the non-const method MyContainer::pointers()
through its attribute m_data
, which is of type MyContainer* const
(at least I think so). I apparently need type MyContainer const*
. Is there an elegant solution to achieve this?std::vector<Entity const*> ret = static_cast<ContainerType const*>(m_data)->pointers();
Is this considered a sensible solution?Disclaimer: I hope this is not a duplicate, it seems that someone else must have had the same problem before. Anyway, I did not manage to resolve this from reading related questions on SO. (The question Const correctness causing problems with containers for pointers? is different, it is about a container of pointers. The issue seems to be related, but the answers did not help me to solve my present problem.)
When you write
m_data->pointers()
you are calling to the same function (the non-const one) because m_data is defined as:
ContainerType* m_data;
that is, a pointer to a non-const objet.
When you use constobj the compiler considers m_data as a const member (you can not change constobj), but in this object, the pointer still points to a non-const object.
I do not know what your application is, but you could consider to add a new function as "cpointers" to return const pointers even if the object is not const.
EDIT: I mean, something like this:
struct MyContainer
{
typedef Value* pointer;
typedef Value const* const_pointer;
std::vector<pointer> pointers() {
std::vector<pointer> ret;
return ret;
}
std::vector<const_pointer> pointers() const {
std::vector<const_pointer> ret;
return ret;
}
std::vector<const_pointer> cpointers() const {
std::vector<const_pointer> ret;
return ret;
}
};
struct MyType
{
typedef MyContainer<Entity> ContainerType;
ContainerType* m_data; // I cannot make this a non-pointer attribute
std::vector<Entity*> pointers() {
std::vector<Entity*> ret = m_data->pointers();
return ret;
}
std::vector<Entity const*> pointers() const {
std::vector<Entity const*> ret = m_data->cpointers(); // error!
return ret;
}
};