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 ofdextents .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 .