Seek example of Range for in C++ 17 where end expression is a different type than the begin expression

In dealing with range for in C++ 17 standard, the end expression type may be different than the begin expression type, which allows for the range be delimited by a predicate. I have been trying to come up with an example with no success so far.

Say we have a container class like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   template <typename T, size_t const Size>
   class dummy_array
   {
      T data[Size] = {};

   public:
      T const & GetAt(size_t const index) const
      {
         if (index < Size) return data[index];
         throw std::out_of_range("index out of range");
      }

      void SetAt(size_t const index, T const & value)
      {
         if (index < Size) data[index] = value;
         else throw std::out_of_range("index out of range");
      }

      size_t GetSize() const { return Size; }
   };


and an iterator type as:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   template <typename T, typename C, size_t const Size>
   class dummy_array_iterator_type
   {
   public:
      dummy_array_iterator_type(C& collection, size_t const index) :
         index(index),
         collection(collection)
      {
      }

      bool operator!= (dummy_array_iterator_type const & other) const
      {
         return index != other.index;
      }

      T const & operator* () const
      {
         return collection.GetAt(index);
      }

      dummy_array_iterator_type const & operator++ ()
      {
         ++index;
         return *this;
      }

   private:
      size_t   index;
      C&       collection;
   };



A template alias makes things easier to read:

1
2
   template <typename T, size_t const Size>
   using dummy_array_iterator = dummy_array_iterator_type<T, dummy_array<T, Size>, Size>;



A suitable begin function could be:


1
2
3
4
5
   template <typename T, size_t const Size>
   inline dummy_array_iterator<T, Size> begin(dummy_array<T, Size>& collection)
   {
      return dummy_array_iterator<T, Size>(collection, 0);
   }


Say that we want the range for to iterate until the value pointed to by the iterator is greater than some value. How can we define a suitable end function to test for this?


Greatly appreciate any help!

Juan
It's called a sentinel. You can use it like this:

(Note: std::sentinel is in C++20 not C++17 so I do a little nasty for this example)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// Don't do this at home kids
/// \todo remove if avaiable
#ifndef __cpp_lib_ranges
namespace std {

struct default_sentinel_t { };

inline constexpr default_sentinel_t default_sentinel{};
}
#endif

class IterateUntilFound {
public:
    IterateUntilFound(const std::vector<int>& values, int stop_value)
        : values(values), stop_value(stop_value)
    {
    }

    int operator*() const {
        return values[idx];
    }

    void operator++() {
        idx++;
    }

    /**
     * Loop keep runinng as lone this returns true.
     */
    bool operator!=(std::default_sentinel_t) const {
        if(idx >= values.size()) return false;
        return values[idx] != stop_value;
    }

    /**
     * \note These member functions enable the use of Stopper with range-based for loops.
     */
    const IterateUntilFound& begin() const noexcept {
        return *this;
    }

    /**
     * Returns a std::default_sentinel_t, which serves as the end iterator.
     * \note These member functions enable the use of Stopper with range-based for loops.
     */
    std::default_sentinel_t end() const noexcept {
        return std::default_sentinel;
    }

private:
    const std::vector<int>& values;
    int stop_value=0;
    size_t idx=0;
};



int main() {
    std::vector<int> values {1,4,2,3,5};

    std::cout << "Stop at 3\n";
    for(auto v : IterateUntilFound(values,3)) {
        std::cout << v << " ";
    }
}
This is a complete rewrite and the example does not address the issues I was looking for. Thanks for the input but maybe I wasn't clear.
I am looking how to define an end() function for the dummy_array template that can be anything (could test any condition to end the iteration)...
I now realize that my

 
bool operator!= (dummy_array_iterator_type const & other) const


should take a different parameter type, something like

 
bool operator!= (dummy_array_predicate_type const & other) const


.

Am I clear?

Regards,
Juan
I got it! Thanks for your example!!

Juan
:)
Registered users can post here. Sign in or register to post.