1

I've read on cppreference that with C++20, it's possible to omit specifying the type aliases reference, pointer and iterator_category when defining a new iterator. In this case, the corresponding aliases in std::iterator_traits will have "default" values. The details of this are a bit confusing to me, so I'm trying to split this topic into answerable questions. So, my first question is: Are all (or some) of these "default" aliases guaranteed to be correct?

As I understand it, the iterator_category tags are based on the C++17 named requirements. If an iterator satisfies the forward iterator requirement (but not the bidirectional requirement), its tag should be forward_iterator_tag.

I'm specifically worried about the distinction between forward_iterator_tag and input_iterator_tag. Forward iterators have to be able to be used in multipass algorithms, but I don't think the compiler checks that this is the case. Are there cases where I can know that the "default" aliases will be correct (e.g. an output iterator is always classified correctly, or the default reference alias is always correct)?

Irgendwhy
  • 125
  • 7

1 Answers1

3

Define "correct". The point of having defaults is to cover the most common cases adequately, while still allowing them to be overridden manually when needed. This implies that, in those cases, the defaults wouldn't be appropriate.

Can you write a type where the defaults are not valid? reference is by default whatever *t returns, so it's pretty hard for the default to be wrong even for proxy iterators.

pointer is defined to be what operator-> would yield, but if no such thing exists, it would be void. But that's OK, because the pointer trait isn't really useful since operator-> isn't even required to be supported by any iterator type.

iterator_category's default is more likely to yield an improper result, but it's not exactly common. Input iterators are less common than other types, so you can easily avoid issues by just specifying the tag when you're writing an input iterator.

It should also be noted that iterator_category specifies conformance to C++17 iterator categories. The C++20 concepts can be overridden by providing an iterator_concept tag specification.

Note also that the ITER_CONCEPT meta-function in C++20 that extracts the iterator tag for the C++20 concepts explicitly bypasses the defaulting mechanism of iterator_category. That is, it only checks the tag you explicitly specify on the iterator itself (either via iterator_concept or iterator_category as a fallback) or on an iterator_traits specialization, not the default that the primary iterator_traits template would produce. So C++20's concepts requires you to specify the tag in some way, despite iterator_traits::iterator_category having a defaulting mechanism.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 1
    It's still optional (that's what the all-caps `ITER_CONCEPT` magic does). The design here is totally not obvious from the wording though. – T.C. Feb 26 '21 at 18:55
  • @T.C.: I didn't notice the whole `iterator_concept` thing as a separate construct from `iterator_category`. That all makes sense now. – Nicol Bolas Feb 26 '21 at 19:48
  • When you say "And an iterator cannot be conformant with any of C++20 iterator concepts without specifying this tag", does that mean that the programmer has to specify the `iterator_concept` tag to be conformant with a concept? Because I'm under the impression that `iterator_category` is enough, which can be omitted. – Irgendwhy Feb 26 '21 at 20:48
  • @Irgendwhy: I misstated what I was going for. It's not that `iterator_concept` *itself* must be specified. It's that ITER_CONCEPT *bypasses* the default `iterator_category`. This means that you are required to specify the tag in some way, with `iterator_concept` overriding `iterator_category`. – Nicol Bolas Feb 26 '21 at 21:57
  • Thanks for your reply and sorry to bother you again, but I don't really follow. My reading of the linked standard text is that it checks the primary template exactly if there is no specialization, but the default isn't a specialization. I've tested defining an input iterator without specifying the `category` or `concept` (similarly to the `WeirdIterator` example from my previous question, but with `operator==` and without `using iterator_category=...`), and `gcc` and `clang` both seem to think it's an `std::input_iterator`. – Irgendwhy Feb 26 '21 at 22:57
  • @Irgendwhy: Pay close attention to the text. `I` is the iterator type. The text says that if `std::iterator_traits` is "a specialization generated from the primary template" (ie: is not an explicit or partial specialization), `ITER_TRAITS(I)` ***is `I` itself***, not `std::iterator_traits`. Note that in standardese, "[specialization](https://timsong-cpp.github.io/cppwp/n4861/temp.spec#4) of a template" is what we in the real world call "template instantiation" – Nicol Bolas Feb 26 '21 at 23:06
  • Thanks for clarifying that, I should've paid closer attention. Unfortunately, I'm still a bit unclear if I get what you're saying with "So C++20's concepts requires you to specify the tag in some way" because not specifying either `category` or `concept` seems to set the `ITER_CONCEPT(I)` to `std::random_access_iterator_tag`, and all iterator concepts except `output_iterator` use `std::derived_from – Irgendwhy Feb 27 '21 at 00:26