Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ : struggle with generic const pointer

I've run into some annoying issues with const-correctness in some templated code, that ultimately boils down to the following observation: for some reason, given an STL-ish Container type T, const typename T::pointer does not actually seem to yeild a constant pointer type, even if T::pointer is equivalent to T::value_type*.

The following example illustrates the problem. Suppose you have a templated function that takes a Container which must meet the STL Random Access Container concept requirements.

template <class Container>
void example(Container& c)
{
    const typename Container::pointer p1 = &c[0]; // Error if c is const
    const typename Container::value_type* p2 = &c[0]; 
}

Then, if we pass this function a const container...

const std::vector<int> vec(10);
example(vec);

...we get an invalid conversion from const int* to int*. But why is const typename Container::pointer not the same as const int* in this example?

Note that if I change const typename Container::pointer to simply typename Container::const_pointer it compiles fine, however, as far as I can tell, the const_pointer typedef is an extension, (I don't see it mentioned in the C++ standard Container Requirements (23.5, Table 65)), and so therefore I don't want to use it.

So how can I obtain a generic, const-correct pointer type from a container T? (I really can't see how to do this without using boost::mpl::if_ along with type_traits to check if the container is constant...but there must be a less verbose way to do this)

Edit: In case it matters, I'm using gcc 4.3.2 to compile this.

like image 690
Charles Salvia Avatar asked Nov 28 '22 11:11

Charles Salvia


2 Answers

It doesn't work because your const does not apply to what you think it applies to. For example, if you have

typedef int* IntPtr;

then

const IntPtr p;

does not stand for

const int* p;

but rather stands for

int* const p;

Typedef-name is not a macro. Once the "pointerness" of the type is wrapped into a typedef-name, there's no way to use it to create a pointer-to-const type anymore. I.e. there's absolutely no way to use the above IntPtr typedef-name to produce an equivalent of

const int* p;

You have to either use to pointee type explicitly (as you did with value_type), or check whether your container defines a different typedef-name, with const already wrapped "inside" (like const_pointer or something like that).

like image 156
AnT Avatar answered Dec 20 '22 01:12

AnT


This:

typename Container::pointer

Has the type int* (in our case). I don't know the terminology, so sorry for that, but pointers point to a type. That is, Container::pointer is a pointer to a mutable T, and adding const is only going to make this a const pointer (not a pointer to const), because Container::pointer has already been defined to point to a mutable T.

It seems only const_pointer, either from the class or your own:

typedef const typename Container::value_type* const_pointer

Will work.

like image 23
GManNickG Avatar answered Dec 20 '22 00:12

GManNickG