Hardik
Hardik

Reputation: 185

Why do algorithms use iterator_traits<T>::value_type instead of iter::value_type?

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

Upvotes: 12

Views: 1210

Answers (2)

Jan Schultke
Jan Schultke

Reputation: 39648

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:

  • your iterator can have an iterator::value_type type alias, which std::iterator_traits will look for
  • you are allowed to define a specialization std::iterator_traits<iterator> yourself

Because 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.


See also: What is the design purpose of iterator_traits?

Upvotes: 17

BoP
BoP

Reputation: 3150

A pointer is a valid iterator type (into an array, for example), but has no value_type member. However, iterator_traits still works for that pointer type.

Upvotes: 11

Related Questions