Created on 2025-07-11.00:00:00 last changed 7 days ago
Proposed resolution:
This wording is relative to N5008.
Modify [span.sub] as indicated:
template<size_t Count> constexpr span<element_type, Count> first() const;
-1- Mandates:
Count <= Extent
is `true`.-2- Hardened preconditions:
Count <= size()
is `true`.-3- Effects: Equivalent to:
return R(
where `R` is the return type.{data(), Count});template<size_t Count> constexpr span<element_type, Count> last() const;
-4- Mandates:
Count <= Extent
is `true`.-5- Hardened preconditions:
Count <= size()
is `true`.-6- Effects: Equivalent to:
return R(
where `R` is the return type.{data() + (size() - Count), Count});template<size_t Offset, size_t Count = dynamic_extent> constexpr span<element_type, see below> subspan() const;
-7- Mandates:
is `true`.Offset <= Extent && (Count == dynamic_extent || Count <= Extent - Offset)
-8- Hardened preconditions:
is `true`.Offset <= size() && (Count == dynamic_extent || Count <= size() - Offset)
-9- Effects: Equivalent to:
return span<ElementType, see below>( data() + Offset, Count != dynamic_extent ? Count : size() - Offset);
-10- Remarks: The second template argument of the returned `span` type is:
Count != dynamic_extent ? Count : (Extent != dynamic_extent ? Extent - Offset : dynamic_extent)
constexpr span<element_type, dynamic_extent> first(size_type count) const;
-11- Hardened preconditions:
count <= size()
is `true`.-12- Effects: Equivalent to:
return R(
where `R` is the return type.{data(), count});constexpr span<element_type, dynamic_extent> last(size_type count) const;
-13- Hardened preconditions:
count <= size()
is `true`.-14- Effects: Equivalent to:
return R(
where `R` is the return type.{data() + (size() - count), count});constexpr span<element_type, dynamic_extent> subspan( size_type offset, size_type count = dynamic_extent) const;
-15- Hardened preconditions:
is `true`.offset <= size() && (count == dynamic_extent || count <= size() - offset
-16- Effects: Equivalent to:
where `R` is the return type.return R(
{data() + offset, count == dynamic_extent ? size() - offset : count});
[ 2025-07-11; Jonathan adds proposed resolution ]
The meaning of those Effects: paragraphs was changed for C++26 by P2447R6 which added the `span(initializer_list)` constructor. A simpler demo is:
The proposed resolution is to use `R(data(), count)` instead of `{data(), count}`. The former always (uniformly) means the same thing, but for the latter the meaning of list-initialization depends on the types. The list-initialization form will choose the initializer-list constructor when `data()` and `count` are both convertible to the element type.bool a[5]{}; std::span<const bool> s(a); std::span<const bool> s2 = s.first(5); assert(s2.size() == 5); // OK in C++23, fails in C++26 assert(s2.data() == a); // OK in C++23, fails in C++26
In section [span.sub], paragraphs p12, p14, and p16 erroneously use the initializer list constructor for span instead of the intended iterator/count constructor.
Specifically, in these paragraphs, the standard states:
Effects: Equivalent to: `return {data(), count};`or some variant of `return {pointer, size}`. As reported in GCC bug 120997 this results in a span that points to invalid stack memory. This can be reproduced on GCC 15.1 for subspan, first, and last: https://godbolt.org/z/r9nrdWscq.
A proposed fix (thanks to Jonathan Wakely) could look like this following:
return span<element_type>(data(), count);
for the affected paragraphs,
which would explicitly specify the constructor used.
History | |||
---|---|---|---|
Date | User | Action | Args |
2025-07-11 09:51:34 | admin | set | messages: + msg14893 |
2025-07-11 09:51:34 | admin | set | messages: + msg14892 |
2025-07-11 00:00:00 | admin | create |