In an algorithm, I can determine the value_type
directly from the iterator via iter::value_type
. Why do algorithms use iterator_traits
to do the same?
#include <iostream>
#include <vector>
#include <iterator>
#include <typeinfo>
using namespace std;
template<typename iter>
void for_each(iter first, iter end)
{
cout << "container value type: "
<< typeid(typename iter::value_type).name()
<< endl;
cout << "container value type: "
<< typeid(typename iterator_traits<iter>::value_type).name()
<< endl;
}
int main()
{
vector<int> v1;
for_each(begin(v1), end(v1));
return 0;
}
Output:
container value type: i
container value type: i
For a type iterator
to be an iterator, it is not necessary to have an iterator::value_type
alias. For example, every pointer is an iterator, namely a ContiguousIterator. The user might write:
int data[] {1, 2, 3, 4};
// iterators will be of type int*
for_each(std::begin(data), std::end(data));
Your code accepting iterators is expected to work with such a function call. Pointers aren't the only problem though:
std::iterator_traits
is a very old construct from C++98, and back in those days, you weren't able to obtain information such as the value_type
of an iterator with decltype()
, because decltype
didn't exist. Nowadays, you could write something like:
auto value = *it;
// and
using value_type = std::decay_t<decltype(*it)>;
for some iterators, but not all.
Be careful, the value_type
can be customized in two ways that break the above code:
iterator::value_type
type alias, which std::iterator_traits
will look forstd::iterator_traits<iterator>
yourselfBecause these customization points exist, you must always use std::iterator_traits
when accessing type information about an iterator. Even in situations where decltype
or auto
look okay, your code could be incorrect because std::iterator_traits
was specialized for the iterator you're working with.