Why is std::iterator deprecated?
From the proposal that suggested its deprecation:
As an aid to writing iterator classes, the original standard library supplied the iterator class template to automate the declaration of the five typedefs expected of every iterator by iterator_traits. This was then used in the library itself, for instance in the specification of
std::ostream_iterator
:template <class T, class charT = char, class traits = char_traits<charT> >
class ostream_iterator:
public iterator<output_iterator_tag, void, void, void, void>;
The long sequence of
void
arguments is much less clear to the reader than simply providing the expected typedefs in the class definition itself, which is the approach taken by the current working draft, following the pattern set in C++14 where we deprecated the derivation throughout the library of functors fromunary_function
andbinary_function
.In addition to the reduced clarity, the iterator template also lays a trap for the unwary, as in typical usage it will be a dependent base class, which means it will not be looking into during name lookup from within the class or its member functions. This leads to surprised users trying to understand why the following simple usage does not work:
#include <iterator>
template <typename T>
struct MyIterator : std::iterator<std::random_access_iterator_tag, T> {
value_type data; // Error: value_type is not found by name lookup
// ... implementations details elided ...
};
The reason of clarity alone was sufficient to persuade the LWG to update the standard library specification to no longer mandate the standard iterator adapators as deriving from
std::iterator
, so there is no further use of this template within the standard itself. Therefore, it looks like a strong candidate for deprecation.
You can also see STL's reasoning in LWG 2438. (h/t T.C.)
As for some other way of doing it, not really. You could basically implement your own version of std::iterator
(which isn't too hard) or manually write out all of those typedefs (which isn't too hard either, and I actually prefer it for clarity).
Why do *_iterators still require typedef something void after removing std::iterator?
Because ISO C++17 std::iteartor_traits
needs all the 5 of these member types in general, even if it is already SFINAE-friendly since C++17. If there are insufficient nested types, the instance of std::iterator_traits
will have no members desired. Currently, this is not changed in the current draft.
See also iterator_traits SFINAE friendliness for rationale of the original proposal.
What is the design purpose of iterator_traits?
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;
...
C++ iterator to string-like types
std::iterator
is not meant to be used that way. It was introduced into the library to support user-defined iterators by providing certain member types like iterator_category
and value_type
. std::iterator
is an empty class and taking it by value is meaningless. Taking it by reference doesn't make much sense either, because iterators do not have to be derived from it. std::iterator
is deprecated since C++17.
LegcayInputIterator
is not a class, but a collection of requirements a type should satisfy. The type itself is not fixed and should be a template parameter. Since C++20, when concepts will become a language feature, you'll be able to write something like this:
template<typename InputIt> requires InputIterator<InputIt>
Example(It begin, It end) { ... }
or
template<InputIterator InputIt>
Example(It begin, It end) { ... }
to check that InputIt
indeed satisfies the requirements of an input iterator. Here InputIterator
is a concept, see here for a particular example. Until then you simply write:
template<typename InputIt>
Example(InputIt begin, InputIt end) { ... }
For example, std::vector
's constructor from a range [first, last)
is declared this way:
template<class InputIt>
vector(InputIt first, InputIt last, const Allocator& alloc = Allocator());
Related Topics
Opencv How to Select a Region of Image Irregularly with Mouse Event? C/C++
Paint a Rect on Qglwidget at Specifit Times
I Want to Generate the Nth Term of the Sequence 1,3,8,22,60 ,164 in Order(1) or Order of (Nlogn)
Why Calling Main() Is Not Allowed in C++
Undefined Reference to 'Stdscr' While Using Ncurses
Load Image with Opencv Mat C++
Why Does This If Condition Fail for Comparison of Negative and Positive Integers
Various Questions About Rsa Encryption
Member Access into Incomplete Type Error
Why Can't I Do Polymorphism with Normal Variables
C++ Add Months to Chrono::System_Clock::Time_Point
Static Control Background Color with C++
How to Use a String as a Variable Name in C++