1

I'm interested in using the iterator syntax for other types of iteration; specifically not that over a container, but rather just to clean up code that functions like iteration.

I already have something working (and maybe - if it isn't broken, don't fix?), but I'd like to know the formal requirements for an iterator for all cases (i.e. the different types of iterators such as constant, and their categories/tags, such as forward).

Here's what how I understand the implementation from cppreference

{
    auto && __range = /* range_expression */;
    auto __begin = __range.begin( );
    auto __end = __range.end( );
    for ( ;
          __begin != __end;
          ++__begin )
    {
        /* range_declaration */ = *__begin;
        /* loop_statement */
    }
}

From what I've gathered, the current requirements are:

  1. __range must contain a non-static rvalue-accessible function member called begin and end that take no parameters
  2. The return from begin must support the pre-increment operator
  3. The return from begin must support the dereference operator
  4. The returns from begin and end must support the does not equal operator

But then I look at the standard and see things like const_iterator and all of the type alias members of the iterator returned from begin and end yet I never see them used (except for something like algorithmic functions, in which case the formal requirements aren't there except for the end-coder, and are not actual requirements for someone making their own iterator).

nowi
  • 437
  • 4
  • 13
  • 2
    It's quite well explained [here](https://en.cppreference.com/w/cpp/iterator). Click on the particular iterator type to see it's formal requirements. There are even some example implementations. – pptaszni Mar 30 '20 at 08:12
  • @pptaszni That is quite the deep rabbit hole of requirements. I also did not see any example implementations but I did only give it a cursory look. Perhaps something spelled out for the layman as an answer for what to look for and where? – nowi Mar 30 '20 at 08:17
  • Mmm sorry, I don't remember where I found reference impl when I was defining my class to be compatible with ranged loops. Anyway, this [topic](https://stackoverflow.com/q/8054273/4165552) covers some of the issues. Anyway, for the [range loop](https://en.cppreference.com/w/cpp/language/range-for) to work you just need `begin` and `end` that return [iterator](https://en.cppreference.com/w/cpp/named_req/Iterator). All the reqs can be found following that 2 links. If you need, I can provide my example implementation. – pptaszni Mar 30 '20 at 08:38
  • Are you really interested only in the range-for loop? – Davis Herring Mar 31 '20 at 14:30
  • @DavisHerring yes – nowi Mar 31 '20 at 20:36

2 Answers2

0

except for something like algorithmic functions, in which case the formal requirements aren't there except for the end-coder, and are not actual requirements for someone making their own iterator

What do you mean by that?

If you want to call a function that takes BidirectionalIterator, you have to implement all the requirements. You don't get to choose which and ignore some, unless you want your code to break when changing versions.

If you mean that you don't see anything using std::iterator_traits<T>::reference, it might be because now we have decltype & auto.

const_iterator is an iterator you get from a const range, which only gives const access to the elements.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Caleth
  • 52,200
  • 2
  • 44
  • 75
-1

There are no contractual requirements for an object to be used with a range-for loop. Unlike the standard library functions, the language defines exactly how the loop is rewritten (with slight updates for different language versions), and it means whatever that replacement means (including being ill-formed). Note that there are possibilities other than the ones you mentioned, like begin and end being found by ADL.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76
  • If it isn't a member function `begin`, then it must be in the same exact scope. Seems like ADL doesn't help much if you don't like the name `begin` :P – nowi Apr 01 '20 at 03:43
  • @nowi: It does allow more cases: it can be a function template, or the “container” can be of a type that is a specialization of a foreign template (that lacks those members!) on one of your types or (oddly) that is an enumeration. – Davis Herring Apr 01 '20 at 03:49