Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sg14::ring_span not compatible with range-v3 (not a semiregular type) #127

Open
seertaak opened this issue Mar 17, 2018 · 5 comments
Open

Comments

@seertaak
Copy link

ring_span is not a semiregular type, because it (and its iterator) lack default constructors. There may be other operations missing. Assuming addition of these does not negatively impact performance, it would be nice for both libraries to interoperate without friction.

@Quuxplusone
Copy link
Contributor

Quuxplusone commented Mar 17, 2018

Default-constructible iterators makes sense to me. Default-constructible ring_span I think makes sense, but could you clarify: what should be the state of a default-constructed ring_span? Would we have to ensure that it was in some sense "empty", or would it be okay to be in a "partially constructed / moved-from" state?

(The answers would presumably be similar to whatever string_view does. I understand that there is an ongoing debate about the validity of string_view{nullptr}, but I believe that string_view{} is already legal in C++17 and does... something. :)

...Although, to be clear, I personally would be fine with sticking to our philosophical guns and saying that rings and iterators do not have partially-formed states, and if you want a "maybe-ring" type, you should use optional<ring_span>. I know that's not how C++ does things though.

@seertaak
Copy link
Author

Sorry for delay in replying. Default-constructable iterators/span should be allowed, and as you suggest should leave the object in a partially-formed state where only valid operation is assignment to properly-initialized span/iterator. It would be "crazy" to do a check :)

I must say: I'm not really an expert in this stuff.

@CaseyCarter
Copy link

CaseyCarter commented Mar 20, 2018

The Ranges TS does not require default-constructed ranges to be in the domain of any range operations (begin, end, empty, size, etc.), so an implementation that only supports destruction/assignment/swap is perfectly reasonable.

There are some requirements on value-initialized forward iterators that we "inherited" from the IS: value-initialized iterators should behave is if they denote the same empty range. Given a value-initialized forward iterator i, that means that i == i, !(i != i) must hold. For a value-initialized random access iterator, equality generalizes to cover distance and ordering so i - i == 0, !(i < i), i <= i, !(i > i), and i >= i must all hold as well.

The TS requires that Views are Semiregular (and therefore DefaultConstructible), but there are no required construction/destruction operations at all for general Ranges. If you want ring_span to model View and participate in View composition, it will need to be Semiregular with amortized O(1) copy/move construction/assignment and default construction. If you only care that it models Range, you can ignore much of this paragraph ;)

@gnzlbg
Copy link

gnzlbg commented Mar 20, 2018

Default-constructible iterators makes sense to me. Default-constructible ring_span I think makes sense, but could you clarify: what should be the state of a default-constructed ring_span? Would we have to ensure that it was in some sense "empty", or would it be okay to be in a "partially constructed / moved-from" state?

What is the motivation for empty() to return false when ring_span is in the "moved-from" state ? If that were allowed, empty() would need a precondition on not being called when the object is in the moved-from state, and all methods with preconditions on empty() (EDIT: and size, and similar methods) would need preconditions on the moved-from state as well.

@Quuxplusone
Copy link
Contributor

Would we have to ensure that it was in some sense "empty", or would it be okay to be in a "partially constructed / moved-from" state?
What is the motivation for empty() to return false when ring_span is in the "moved-from" state?

Not necessarily "false"; more like what you said next: there could be a precondition that you're not allowed to call .empty() on a moved-from object. The rationale is that empty() might be implemented as size()==0, and size() might be implemented as end() - begin(), and calling either begin() or end() on a moved-from object might access through a null pointer.

Casey's answer implies that this is okay as far as the Concepts are concerned:

The Ranges TS does not require default-constructed ranges to be in the domain of any range operations (begin, end, empty, size, etc.)

And yes, this is super confusing and ugly, thanks for asking. "I personally would be fine with sticking to our philosophical guns and saying that rings and iterators do not have partially-formed states, and if you want a "maybe-ring" type, you should use optional<ring_span>." 🙂

Anyway, pull requests welcome AFAIC and I'll happily merge whatever looks good to people; I'm unlikely to initiate any patches on my own.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants