operator-> is not a requirement for most iterators, so remove it. To
account for this change, the common_iterator.operator-> test needs to
be refactored quite a bit -- improve test coverage while we're at it.
Details
- Reviewers
• Quuxplusone - Group Reviewers
Restricted Project - Commits
- rG553ab7a090dc: [libc++] Remove operator-> from iterator archetypes that don't need it
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
libcxx/test/support/test_iterators.h | ||
---|---|---|
255–266 | (A) please don't reopen namespace std, but also (B) please don't specialize pointer_traits. |
libcxx/test/support/test_iterators.h | ||
---|---|---|
255–266 |
Can you please explain why that's bad? That seems gratuitous -- pointer_traits is explicitly made to be customized, no? Arguably, if I could remove all that complexity and only have element_type, that would indeed better, but I don't see why specializing pointer_traits would be bad in itself. Edit: Nope, that doesn't work, I have to keep operator->().
Yes, that's my goal. The reason is to make congituous_iterator more minimal, just like the other changes we did to e.g. cpp17_input_iterator to remove default-constructibility. Because it makes it more useful for testing. |
I don't agree with this direction, but I think the only hill I'll particularly die on is "don't reopen namespace std."
libcxx/test/std/iterators/predef.iterators/iterators.common/arrow.pass.cpp | ||
---|---|---|
28–38 | Consider { Common common(iter); std::same_as<IteratorWithArrow> auto r1 = static_cast<Common&>(common).operator->(); std::same_as<IteratorWithArrow> auto r2 = static_cast<Common&&>(common).operator->(); std::same_as<IteratorWithArrow> auto r3 = static_cast<const Common&>(common).operator->(); std::same_as<IteratorWithArrow> auto r4 = static_cast<const Common&&>(common).operator->(); assert(base(r1) == buffer); } just to hit the move cases as well. (If IteratorWithArrow were move-only, would there be no operator->? ....waitaminute. You have an infinite loop in your operator->, don't you? IteratorWithArrow::operator->() can't return another IteratorWithArrow! It should be returning int*.) (And I think I just remembered that common_iterator doesn't work with move-only iterator types, right? because it's meant as an adaptor to produce a C++17 iterator, which must be copyable by definition?) | |
libcxx/test/std/iterators/predef.iterators/iterators.common/iterator_traits.compile.pass.cpp | ||
94 | The code on the left strikes me as weird. But whatever, I'm getting deja vu to a conversation with @CaseyCarter where he said nobody cares about the value of ::pointer. :) | |
libcxx/test/support/test_iterators.h | ||
255–266 |
https://quuxplusone.github.io/blog/2021/10/27/dont-reopen-namespace-std/
Because user iterators won't specialize pointer_traits. I suppose there is a tension here between "Keep test code simple; eliminate metaprogramming; make test code realistic" and "Make test code that stress-tests the corner cases." For example, we =delete the comma operator on all of these iterators (and should delete operator& too, probably) — that's more complicated than necessary, and isn't realistic, but it does stress-test the corner cases. So maybe "let's specialize pointer_traits for all these iterators to make sure all our algorithms respect the specialized pointer_traits" is a good suggestion on par with "Let's =delete the comma operator for all these iterators." Personally I don't think it meets the bar; it's a lot of complexity for what it gives us IMO, especially compared to the simplicity of |
Hopefully we can agree that this is an improvement if I keep operator-> as a way to define contiguous_iterator?
libcxx/test/std/iterators/predef.iterators/iterators.common/arrow.pass.cpp | ||
---|---|---|
28–38 | Fixed by removing IteratorWithArrow altogether.
Yes, that's right. | |
libcxx/test/support/test_iterators.h | ||
255–266 | Okay, I sat on this for a while, but I think I agree. In the next iteration I'll remove operator-> only from the archetypes that truly don't need it for anything, like cpp17_input_iterator & friends. I'll keep it on contiguous_iterator. |
LGTM % the check lambda stuff (which I won't insist on, anyway). Thanks!
libcxx/test/std/iterators/predef.iterators/iterators.common/arrow.pass.cpp | ||
---|---|---|
24–41 | Nit: Why not good old-fashioned template<class It> void test_case_1() { // Case 1: http://eel.is/c++draft/iterators.common#common.iter.access-5.1 ~~~ } template<class It> void test_case_2() { etc? The whole check.operator()<T>(); thing works, but it doesn't look nice. | |
libcxx/test/std/iterators/predef.iterators/iterators.common/iterator_traits.compile.pass.cpp | ||
94 | For my information, did we ever figure out why the old code thought it'd be const Iter&? |
libcxx/test/std/iterators/predef.iterators/iterators.common/arrow.pass.cpp | ||
---|---|---|
24–41 | I actually applied this suggestion, and it resulted in the test case definition and the types it is being called on being further apart, which seemed to decrease legibility. So I'd be in favour of keeping the current approach (even though I agree check.operator()<T>() doesn't look pretty). | |
libcxx/test/std/iterators/predef.iterators/iterators.common/iterator_traits.compile.pass.cpp | ||
94 | Frankly, I did not investigate because int* is what I would have expected all along. However, thinking about it right now: http://eel.is/c++draft/iterators.common#common.iter.access-5.1 says that we return return get<I>(v_);, when the iterator has operator->, and that is Iter const& here. When we remove operator-> from the underlying iterator, we instead return addressof(*get<I>(v_)), and that is int*, as we're seeing in the diff after. |
Consider
just to hit the move cases as well. (If IteratorWithArrow were move-only, would there be no operator->? ....waitaminute. You have an infinite loop in your operator->, don't you? IteratorWithArrow::operator->() can't return another IteratorWithArrow! It should be returning int*.)
(And I think I just remembered that common_iterator doesn't work with move-only iterator types, right? because it's meant as an adaptor to produce a C++17 iterator, which must be copyable by definition?)