Boost logo

Boost :

From: John Maddock (John_Maddock_at_[hidden])
Date: 2000-10-19 05:48:30


Jesse,

>I dunno about this. It seems to me that if you need to special case const
>types then you'll write code to do so using is_const and remove_const. If
>special casing isn't required it'd be nice to not have to muck around with
>remove_const.

First let me say that the two approaches are orthogonal: that is one of the
reasons that we agonized over this for so long in the first place.

>The pointer case is similiar: the first sentence in section 3.9.3 can be
>read to mean that const pointer types are not pointer types. Is this
>interpretation correct?

I'm tempted to say that what was in the mind of the committee isn't that
relevant here (they probably didn't even think about this), the point is
that the semantics follow the letter of the standard as written, and much
more to the point are actually useful as written, let me try and present
some examples to make my case:

Example 1: Specialising vector for pointers.

Ignoring allocators we might implement vector like this:

template <class T, bool>
vector_base
{
/* default normal vector imp*/
};

template<>
vector_base<void*, true>
{
/* special case for pointers*/
}

template <class T>
vector_base<T, true> : vector_base<void*, true>
{
/* simple wrapper*/
};

template <class T>
class vector : vector_base<T, is_pointer<T>::value>
{
/* simple wrapper*/
};

Now consider what happens if T is int* const: should we still be using the
void* specialisation for this?

I think the answer is no, in fact cv-qualified types are not even
containable at all, there is no way we can rely on being able to
instantiate vector<const int> or vector<int*const> (because a const-type is
not an assignable type), nor can we instantiate vector<int volatile>
(because the copy constructible guarantees break down).

Example 2: A pointer is always an iterator.

This is true provided the pointer is not cv-qualified, int*const is not
incrementable, or assignable for example. The standard acknowledges this
too: there are no specialisations of iterator_traits for cv-qualified
pointers: cv-qualified pointers are not complete iterators (I'm not sure if
this was a design decision or an omission, however I think that the
omission is correct).

Example 3: A pointer is always trivially assignable: but not if it is
cv-qualified.
Example 4: A pointer is always trivially copyable: but not if it is
volatile-qualified.

Example 5: We can use these classes for static assertions:
In the rational class, we may require that the template argument is an int:

template <class T>
class rational
{
BOOST_STATIC_ASSERT(is_integer<T>::value);
/*details*/
};

However in this case "must be an int" means "must be a non-cv-qualified
int", so the current rules are correct in this case.

I'm going to stick my neck out here and say that instantiating a template
on a cv-qualified type is almost always an error, there are clearly
exceptions (std::pair springs to mind), but I believe that they are
exceptions, in fact I've tried hard to think of a non-trivial example of
where is_pointer would be used without regard to cv-qualifiers and I've
failed.

Jesse, did you have some particular usage examples in mind to contradict
this - I'm still open to persuasion here.

Yours-with-neck-stuck-out-waiting-for-Madame-Guillotine's-kiss!
-John.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk