c++templatesstlconstants

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 yield 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)

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


Solution

  • 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).