Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between iterator_category and iterator_concept in C++20?

C++20 brings a more powerful iterator system, one of them is to introduce iterator_concept on the basis of iterator_category.

I found that the iterator_concept and iterator_category of many iterators in C++20 are inconsistent. Take the most famous iota_view as an example:

using R = decltype(views::iota(0));
static_assert(random_access_range<R>);

using I = ranges::iterator_t<R>;
static_assert(same_as<typename I::iterator_category, input_iterator_tag>);
static_assert(same_as<typename I::iterator_concept,  random_access_iterator_tag>);

Although R models random_access_range, the iterator_category of its iterator is just an input_iterator_tag, which is inconsistent with the iterator_concept.

Why does C++20 introduce iterator_concept? What is its purpose? If I implement my own iterator, how do I define iterator_concept and iterator_category correctly? Does iterator_category still have a meaning in C++20?

like image 728
康桓瑋 Avatar asked May 19 '21 15:05

康桓瑋


People also ask

What is Iterator_category?

Iterator_category is an iterator tag function: it is used to determine the category to which an iterator belongs. Specifically, every iterator must belong to a type that is a model of the concept Output Iterator, Input Iterator, Forward Iterator, Bidirectional Iterator, or Random Access Iterator.

What does iterator_ traits?

iterator_traits are used within algorithms to create local variables of either the type pointed to by the iterator or of the iterator's distance type. The traits also improve the efficiency of algorithms by making use of knowledge about basic iterator categories provided by the iterator_category member.

What is forward iterator?

Forward Iterator is a combination of Bidirectional and Random Access iterator. Therefore, we can say that the forward iterator can be used to read and write to a container. Forward iterators are used to read the contents from the beginning to the end of a container.

What is an input iterator C++?

Input Iterator is an iterator used to read the values from the container. Dereferencing an input iterator allows us to retrieve the value from the container. It does not alter the value of a container. It is a one-way iterator.

What is iterator in C++ with example?

Iterator is an object, which is used to iterate over an iterable object using __next__ () method. Iterators have __next__ () method, which returns the next item of the object. Note that every iterator is also an iterable, but not every iterable is an iterator.

What is the difference between iterator and iterable?

Iterator is an object, which is used to iterate over an iterable object using __next__ () method. Iterators have __next__ () method, which returns the next item of the object. Note that every iterator is also an iterable, but not every iterable is an iterator. For example, a list is iterable but a list is not an iterator.

What is the difference between c++17 and C++20 iterators?

C++20 introduces a new system of iterators based on concepts that are different from C++17 iterators. While the basic taxonomy remains similar, the requirements for individual iterator categories are somewhat different. C++20 also provides a set of concepts and related utility templates designed to ease constraining common algorithm operations.

How many types of iterators are there in Python?

The whole list is as given below: Types of iterators: Based upon the functionality of the iterators, they can be classified into five major categories: Input Iterators: They are the weakest of all the iterators and have very limited functionality.


Video Answer


1 Answers

There are differences between the C++17 (C++98) iterator model and the C++20 Ranges iterator model that are not backwards compatible. The two big ones are:

  1. The C++98 model requires that forward iterators have a reference that is either value_type& or value_type const&.
  2. The C++98 model does not allow for contiguous iterators. The strongest category was random_access.

The consequence of (1) is pretty significant - it means that if you have an iterator that returns a prvalue (whether proxy reference or not), it can never be stronger than an input iterator. So, views::iota(1, 10), despite easily being able to support random access, is only, at best, a C++98 input range.

However, you can't just... remove this requirement. Existing code that assumes C++98 iterators and uses iterator_category to make judgements is perfectly within its rights to assume that if iterator_category is, say, bidirectional_iterator_tag, that its reference is some kind of lvalue reference to value_type.

What iterator_concept does is add a new C++20 layer that allows an iterator to both advertise its C++98/17 category and, distinctly, advertise its C++20 category. So going back to the iota_view<int, int> example, that view's iterator has iterator_category set to input_iterator_tag (because the reference is a prvalue and so it does not satisfy the old requirements for even forward) but its iterator_concept is set to random_access_iterator_tag (because once we drop that restriction, we can easily support all the random access restrictions).

In [iterator.concepts.general], we have this magic function ITER_CONCEPT(I) which helps us figure out what tag to use in C++20.

The issue with (2) is that it was hard to just add a new contiguous_iterator_tag before due to the way that various C++98/17 code would check for that tag (lots of code might check for exactly random_access_iterator_tag). The iterator_concept approach avoids this problem by also introducing concepts that directly check the right thing for you (i.e. the random_access_iterator concept checks that ITER_CONCEPT(I) derives from random_access_iterator_tag, not that it simply is that).


Guidelines:

  • If you're using an iterator in C++17, use std::iterator_traits<I>::iterator_category.
  • If you're using an iterator in C++20, use the std::meow_iterator concepts
  • If you're writing an iterator in C++17, add the iterator_category alias and make sure you follow the forward iterator/reference restriction (or... don't, but it's on you)
  • If you're writing an iterator in C++20, follow the guidance in P2259 which has a good description of the problem and how and when to provide the iterator_category and iterator_concept type aliases.
like image 54
Barry Avatar answered Nov 15 '22 07:11

Barry