gnzlbg / static_vector

A dynamically-resizable vector with fixed capacity and embedded storage

Home Page:https://gnzlbg.github.io/static_vector

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Incorporate Andrzej feedback

gnzlbg opened this issue · comments

  • (FIXED in 6231af9) Declarations of static_vector's copy and move constructors (in 5.1) are duplicated: either they were pasted twice or you intended another pair of constructors.

  • Description of move constructor imprecise: it says the result "should be equal" to the original, but formally vectors may not be determined to be equal if the stored value type is not comparable. Either do not define semantics and rely on these from the requirments on sequence containers (vector does this), or use semantics as specified for optional that does not refer to "being equal".

  • (FIXED in 67afb69) signatures of cbegin() and crbegin() are missing const.

  • (FIXED in 7c2d8b9) definition of swap() -- either do not provide it and rely on requirements on sequence containers (like vector does) or add a remark that it should not participate in overload resolution unless is_move_constructible_v and is_swappable_v is true.

  • (FIXED in b3a6f7a) In a number of places you have: [first, last] or [begin(), end()] to represent a range. It is incorrectly a right-closed range. Instead it should be: [first, last) and [begin(), end()).

  • (FIXED in f85efa6) "Requires" clause is now deprecated. Instead, either use "Mandates" (compiler error if expectation not met) or "Expects" (UB if expectation not met), or say "Remarks: this function shall not participate in overload resolution unless condition C is true" (i.e. requires in the concepts-lite sense)

cc @akrzemi1

  • Description of move constructor imprecise: it says the result "should be equal" to the original, but formally vectors may not be determined to be equal if the stored value type is not comparable. Either do not define semantics and rely on these from the requirments on sequence containers (vector does this), or use semantics as specified for optional that does not refer to "being equal".

About this point, these move constructor requirements are defined in container.requirements (see rv) as:

Ensures: u shall be equal to the value that rv had before this construction

which is the exact wording the current clause uses. I'd agree that this is not strictly needed, but note that this proposal modifies the "Note A" and "Note B" in the table to include static_vector along with array (since they have slightly different complexities than the other containers), so I thought that this detail was something worth repeating.

  • definition of swap() -- either do not provide it and rely on requirements on sequence containers (like vector does) or add a remark that it should not participate in overload resolution unless is_move_constructible_v and is_swappable_v is true.

I suppose that you are referring to the non-member swap here, which uses this wording in utility.swap, right? (I fixed it here: 7c2d8b9).

  • In a number of places you have: [first, last] or [begin(), end()] to represent a range. It is incorrectly a right-closed range. Instead it should be: [first, last) and [begin(), end()).

The only occurrence of [first, last] is in erase(first, last), where the proposal states:

Expects: [first, last] in range [begin(), end()].

AFAIK erase(begin(), end()) shall not trigger UB, but if I change the Expects to [first, last) then it would and users would need to change that to erase(begin(), end() - 1), right? Or what am I missing?

The occurrences of [begin(), end()] are also only in the erase methods for the same reason as above, except that erase(pos) should also work for erase(end()).

constexpr iterator erase(const_iterator position);
  • Effects: Removes the element at position, destroys it, and invalidates
    references to elements after position.

  • Expects: position in range [begin(), end()].

This means that position can be end() exactly, which is wrong: you do not want to erase the non-existing element *end().

constexpr iterator erase(const_iterator first, const_iterator last);
  • Effects: Removes the elements in range [first, last), destroying them,
    and invalidating references to elements after last.

  • Expects: [first, last] in range [begin(), end()].

I guess this is technically correct, however it is very disturbing. It would be more natural to specify it as:

  • Expects: [first, last) in range [begin(), end()).

Regarding the moves, I will try to contact LEWG to ask for guidance.

This means that position can be end() exactly, which is wrong: you do not want to erase the non-existing element *end().

Indeed, I don't know what I was thinking.

It would be more natural to specify it as:

That does sound like a more natural way to put it.

I will try to contact LEWG to ask for guidance.

Thank you, I really appreciate it :)

Unfortunately, LEWG adjourned their sessions for Kona meeting. I think the best approach would be to leave the wording as it is. You are correct that this the text already used by the Standard. Maybe except for "move-inserts", but that is quite unambiguous.

The last commit changes the ranges of erase to the ones suggested, so I'm going to close this issue.

Maybe except for "move-inserts", but that is quite unambiguous.

If you have a particular proposal about how to tweak this, or if you hear differently from LEWG, please let me know!

Also, sincerely, thank you for taking the time to go through the wording, writing down and sending me your feedback, putting up with my questions! It all takes a lot of time and I really do appreciate it!