Home Iterators with conditional end 🏁
Post
Cancel

Iterators with conditional end 🏁

Iterators are one of the core concepts of C++. C++ has its own corresponding iterator class for each container class (set/vector/list/…) used to access its own data.

The class for which the corresponding iterator class is defined ought to have the begin() and end() methods, which return the iterator objects. The iterator class ought to have the opeator++() and operator*() methods. The presence of these methods is sufficient to use the iterator in various standard methods and in the range-based for loop.

Usually iterators iterate over all objects from begin() to end():

1
2
3
4
5
6
7
8
    const std::vector<int> vec{1, 3, 5, 7, 9};
    // the code below is equivalent to `for (int value : vec) { /* ... */ }`
    auto __begin = vec.begin();
    auto __end = vec.end();
    for ( ; __begin != __end; ++__begin) {
        int value = *__begin;
        /* do something with `value`... */
    }

However, there are cases when the end() cannot be calculated in advance and it is necessary to check at every step whether we should exit the loop.

In the C++20 standard, there is such an approach:

  1. Introduce an empty class std::default_sentinel_t.
  2. The end() method of the container class should return an object of the mentioned empty class:
    1
    2
    3
    
     std::default_sentinel_t end() { 
         return {}; 
     }
    

    (the begin() method will keep returning a normal iterator object)

  3. The iterator class must define a comparison operator with objects of the empty class:
    1
    2
    3
    
     bool operator==(std::default_sentinel_t) const { 
         return /* some condition */; 
     }
    

As the result, the old code with iterators works as before, but ends only when the comparison operator returns true!

What are the real use cases:

This post is licensed under CC BY 4.0 by the author.

Simulating physics in C++ using numerical analysis 🌊

How does the compiler measure compilation speed? πŸ•°