Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
(Thanks to many WG21 experts for their comments and feedback into this note.)
Add the following typedef to GSL
and recommend
gsl::index
for all container indexes/subscripts/sizes.Rationale
The Guidelines recommend using a signed type for subscripts/indices. See ES.100 through ES.107. C++ already uses signed integers for array subscripts.
We want to be able to teach people to write "new clean modern code" that is simple, natural, warning-free at high warning levels, and doesn’t make us write a "pitfall" footnote about simple code.
If we don’t have a short adoptable word like
index
that is competitive withint
andauto
, people will still useint
andauto
and get their bugs. For example, they will writefor(int i=0; i<v.size(); ++i)
orfor(auto i=0; i<v.size(); ++i)
which have 32-bit size bugs on widely used platforms, andfor(auto i=v.size()-1; i>=0; ++i)
which just doesn't work. I don’t think we can teachfor(ptrdiff_t i = ...
with a straight face, or that people would accept it.If we had a saturating arithmetic type, we might use that.
Otherwise, the best option is
ptrdiff_t
which has nearly all the advantages of a saturating arithmetic unsigned type, except only thatptrdiff_t
still makes the pervasive loop stylefor(ptrdiff_t i=0; i<v.size(); ++i)
emit signed/unsigned mismatches oni<v.size()
(and similarly fori!=v.size()
) for today's STL containers. (If a future STL changes itssize_type
to be signed, even this last drawback goes away.)However, it would be hopeless (and embarrassing) to try to teach people to routinely write
for (ptrdiff_t i = ... ; ... ; ...)
. (Even the Guidelines currently use it in only one place, and that's a "bad" example that is unrelated to indexing`.)Therefore we should provide
gsl::index
(which can later be proposed for consideration asstd::index
) as a typedef forptrdiff_t
, so we can hopefully (and not embarrassingly) teach people to routinely writefor (index i = ... ; ... ; ...)
.Q&A
Why not just tell people to write
ptrdiff_t
? Because we believe it would be embarrassing to tell people that's what you have to do in C++, and even if we did people won't do it. Writingptrdiff_t
is too ugly and unadoptable compared toauto
andint
. The point of adding the nameindex
is to make it as easy and attractive as possible to use a correctly sized signed type.Should it be called
index_t
, following the C convention for typedefs? Please no. We are competing withauto
andint
, both of which have pitfalls for the unwary, and the point of adding this common name is to make it as easy and attractive as possible to use routinely. The extra characters_t
(one of which requires hitting Shift; seriously) are a significant uglification for this type that we want to be pervasively used, and I fear those two extra characters will cause needless impedance compared toauto
andint
.Is
ptrdiff_t
big enough? Yes. Standard containers are already required to have no more elements than can be represented byptrdiff_t
, because subtracting two iterators must fit in adifference_type
.But is
ptrdiff_t
really big enough, if I have a built-in array ofchar
orbyte
that is bigger than half the size of the memory address space and so has more elements than can be represented in aptrdiff_t
? Yes. C++ already uses signed integers for array subscripts. So useindex
as the default option for the vast majority of uses including all built-in arrays. (If you do encounter the extremely rare case of an array, or array-like type, that is bigger than half the address space and whose elements aresizeof(1)
, and you're careful about avoiding truncation issues, go ahead and use asize_t
for indexes into that very special container only. Such beasts are very rare in practice, and when they do arise often won't be indexed directly by user code. For example, they typically arise in a memory manager that takes over system allocation and parcels out individual smaller allocations that its users use, or in an MPEG or similar which provides its own interface; in both cases thesize_t
should only be needed internally within the memory manager or the MPEG class implementation.)Will this still leave noisy signed/unsigned mixed comparison warnings? Hopefully not. The guidance in this PR allow-lists comparisons between
index
(akaptrdiff_t
) and eithersizeof
or a container.size()
for compatibility with the current standard language and library. (Thanks to Robert Douglas for pointing out thesizeof
noisy case.)Why not use a saturating unsigned type? Then those big arrays would work, and I wouldn't get any signed/unsigned comparison mismatch warnings even using today's standard containers. Because we don't have a general-purpose saturating type in the standard. If we get one, we can revisit and consider using it.
Should
gsl::span
be updated to useindex
? Yes. In fact, it effectively already does so because it usesptrdiff_t
. Once we addindex
, GSL should change all of its other uses ofptrdiff_t
to beindex
for stylistic consistency.