Why is std::iterator_traits::value_type non-const even for a const_iterator?

2.5k Views Asked by At

In the C++ standard library, why is

std::iterator_traits<const T*>::value_type

the same type as

std::iterator_traits<T*>::value_type

Why it is designed like that? Shouldn't the first be const T and the second only T? How are you supposed to take the underlying const-correct type of an iterator? I know you can write your own template class and specialization and get it from

std::iterator_traits<const T*>::pointer

but shouldn't there be a member typedef that holds it?

2

There are 2 best solutions below

6
On BEST ANSWER

It allows me to do this:

std::iterator_traits<I>::value_type val = *iter;
val += 5;
doSomething(val);

But that's harder if value_type is const, because I need to use remove_const.

If I don't want to get a modifiable value then it doesn't matter whether value_type is const or not:

const std::iterator_traits<I>::value_type cval = *iter;
std::iterator_traits<I>::reference        ref  = *iter;

Both of these work for const iterators and non-const iterators, and both work whether value_type is const or not, but the first example only works for const iterators if their value_type is non-const.

How are you supposed to take the underlying const correct type of an iterator?

An iterator doesn't necessarily have an underlying type of its own, an iterator usually refers to some range or some collection, and that collection is what has an underlying type. e.g std::list<int>::const_iterator's value_type is std::list<int>::value_type, which is int not const int.

You don't necessarily want to know what the underlying type is anyway, it's more likely you want to know what the result of *iter is, and that's what iterator_traits<I>::reference tells you.

4
On

Constness doesn't matter for the value type, since a value implies a copy. The std::iterator_traits<const T*>::reference is a const T& however.

For example, you can write this function:

template <class Iterator>
typename std::iterator_traits<Iterator>::value_type getValue(Iterator i)
{
  return *i;
}

and it works perfectly fine whether Iterator is a const T * or a T *.