Reputation: 119
The C++ standard library has both iterator
and iterator_traits
templates defined. It seemed that in general, the iterator_traits
just extracts properties that defined explicitly in iterator
. If a iterator_traits
is to be used, one can use the corresponding iterator
directly. If a specialization of certain type (e.g. T*
) is required, a specialization of iterator
could match the requirement. What's the benefit this indirection?
Upvotes: 2
Views: 1331
Reputation: 238361
It seemed that in general, the iterator_traits just extracts properties that defined explicitly in iterator. If a iterator_traits is to be used, one can use the corresponding iterator directly.
Not all iterators can type aliases as members.
What's the benefit this indirection?
To allow all iterators to have a uniform interface. More specifically, pointers are iterators too and as non-class types, pointers cannot have members.
So, when for example the user of an iterator wants the answer to the question "What is the type of the object pointed by an_iterator_type
", they cannot use an_iterator_type::value_type
because that cannot be defined for all iterators - specifically pointers. What they can use is std::iterator_traits<an_iterator_type>::value_type
which can be defined for all iterators - including pointers. That is the purpose of std::iterator_traits
.
The standard defines the std::iterator_traits<T*>
specialisations for pointers. Although you can, you don't need to define specialisations for custom iterator types because you can instead define the types as members, which will be used by the generic definition of std::iterator_traits
.
The intention of std::iterator
was to be optionally used as a base class to help define the member types for custom iterators. However its use was never necessary, it is considered to be a flawed design and its use has long been discouraged. Since C++17, it has been deprecated and it may be removed from future standards.
An example that hopefully demonstrates the problem of the design of std::iterator
:
// using the deprecated std::iterator
struct iterator : std::iterator<
std::input_iterator_tag, // OK so far
long, // can you guess what member this argument defines?
long, // how about this?
const long*, // you can probably guess this one
long> // still, no clue
{
...
// recommended way without using std::iterator
struct iterator
{
using iterator_category = std::input_iterator_tag;
using value_type = long;
using difference_type = long;
using pointer = const long*;
using reference = long;
...
Upvotes: 13