1. Revision history
1.1. R0
R0 published 2024-02-15 and reviewed by LEWG 2024-03-05. Poll results follow.
POLL: We want to make a breaking change to
to fix the issue presented in P2389R0.
Results (SF/F/N/A/SA): 0/8/6/4/1.
-
Attendance: 25
-
Author’s Position: WF
-
Outcome: No consensus for a change
POLL: Vote once for your preferred name option:
-
: 0 votesstd :: dexts -
: 11 votesstd :: dims -
Please explore a new name (in the reflector): 2 votes
POLL: Forward P2389R1 to LWG for C++26
(which will be P2389R0 modified to add a new facility (
) as suggested,
but with the last param as the type defaulted to
)
(to be confirmed with a library evolution electronic poll).
Results (SF/F/N/A/SA): 5/8/2/0/0.
-
Attendance: 26
-
Author’s Position: SF
-
Outcome: Strong consensus in favor
1.2. R1
R1, to be published 2024-03-12, includes the following changes.
-
Discuss and implement the above LEWG poll decisions
-
Add wording
-
Discuss freestanding implications (we think there are none)
-
Add link to implementation
-
Correct use of
in nonwording sectionsextents -
Add Mark Hoemmen to author list
2. Background
[P0009R18] added
, a non-owning multidimensional span abstraction
to the C++ Standard Library.
It is excellent and flexible, allowing users to customize customize data
layout, access method, and index type.
However, this flexibility often comes with verbosity.
The length of each dimension (the extent) of an
are represented by an
object, and each extent may be expressed either statically or
dynamically. Use cases based on P0009R18’s wording would look like this.
// All static extents mdspan < float , extents < 64 , 64 , 64 >> a ( d ); // All dynamic extents mdspan < float , extents < dynamic_extent , dynamic_extent , dynamic_extent >> a ( d , 64 , 64 , 64 ); // Mixed static and dynamic extents mdspan < float , extents < 64 , dynamic_extent , 64 >> a ( d , 64 );
[P2299R3] sought to improve
s usability
for one of the most common cases: when all extents are dynamic.
First, it added deduction guides
to make class template argument deduction (CTAD) work
for
and
.
std :: vector < float > storage ( 64 * 64 ); mdspan a ( storage . data (), 64 , 64 ); // All dynamic.
However, CTAD does not help in all situations. For example, it cannot be used when declaring a class member or a function parameter.
struct X { std :: mdspan < float , std :: extents < std :: dynamic_extent , std :: dynamic_extent , std :: dynamic_extent >> a ; }; void f ( std :: mdspan < float , std :: extents < std :: dynamic_extent , std :: dynamic_extent , std :: dynamic_extent >> a );
To simplify these cases, [P2299R3] also added
,
a template alias for an
with
dynamic extents.
template < std :: size_t N > using dextents = /* ... */ ; struct X { std :: mdspan < float , std :: dextents < 3 >> a ; }; void f ( mdspan < float , std :: dextents < 3 >> a );
3. Problem
Originally,
and
used a fixed index type (
).
However, the signedness and size of the index type
can affect performance in certain cases.
So, [P2553R1] parameterized the index type used by
and
.
As a part of this change, an index type template parameter was added to
.
template < class IndexType , std :: size_t Rank > using dextents = /* ... */
This change has made using
more verbose, which is unfortunate, as
the main purpose of
was to make common uses as simple as possible.
struct X { std :: mdspan < float , std :: dextents < std :: size_t , 3 >> a ; }; void f ( mdspan < float , std :: dextents < std :: size_t , 3 >> a );
Index type customization is an important feature for
to support, but it
is not something that most users will need to use or think about.
If they do need it, they can always use the more verbose
.
4. Proposed Changes
In R0, we originally proposed removing the index type parameter from
and making it always use
as the index type.
For example, instead of typing
as an alias for
,
users would type
.
This would have been a source-breaking change.
As of the publication date,
MSVC’s STL and LLVM’s libc++ are already shipping
.
GCC’s libstdc++ is not shipping
yet.
However, since
is a template alias,
it would have had no ABI impact.
LEWG reviewed R0 and voted against the breaking change.
Instead, LEWG approved our alternative design:
leave
alone, but add a new
template alias.
LEWG asked us to adjust the
design
by adding an index type template parameter as its _last_ template parameter,
and defaulting it to
.
The resulting alias looks like this.
template < size_t Rank , class IndexType = size_t > using dims = dextents < IndexType , Rank > ;
Before adding this alias, the above use cases where CTAD could not be used would look like this.
struct X { // Member declaration std :: mdspan < float , std :: dextents < std :: size_t , 3 >> a ; }; // Function parameter void f ( std :: mdspan < float , std :: dextents < std :: size_t , 3 >> a );
After adding this alias, those two use cases would look like this.
struct X { // Member declaration std :: mdspan < float , std :: dims < 3 >> a ; }; // Function parameter void f ( mdspan < float , std :: dims < 3 >> a );
The result is even more compact than
.
It also abbreviates a more familiar word, "dimensions."
5. Note on freestanding
P2833R2,
adopted in Kona 2023, added an
comment
to the beginning of the [mdspan.syn] synopsis.
In our view, our proposal would not change this freestanding status.
6. Implementation
We have implemented the proposal as Pull Request 324 in the reference mdspan implementation.
7. Wording
Text in blockquotes is not proposed wording, but rather instructions for generating proposed wording. Markup
@
indicates that the text "something something else" is to be rendered in italics, without the additional_something something else_ @@
or_ .
_ @Make the following changes to the latest C++ Working Draft as of the time of writing. All wording is relative to the latest C++ Working Draft.
In [version.syn], increase the value of the
macro by replacing YYYMML below with the integer literal encoding the appropriate year (YYYY) and month (MM).
__cpp_lib_mdspan
#define __cpp_lib_mdspan YYYYMML // also in <mdspan>
In the
header synopsis [mdspan.syn], after the declaration of
< mdspan > , add the following declaration of
dextents .
dims
// [mdspan.extents.dims], @_alias template_@ `dims` template < size_t Rank , class IndexType = size_t > using dims = @_see below_ @;
Immediately after section [mdspan.extents.dextents], insert a new section "Alias template
" [mdspan.extents.dims] with the following wording.
dims
template < size_t Rank , class IndexType = size_t > using dims = @_see below_ @;
Result: A type
that is a specialization of
such that
is true
, and
denotes
.