
1. std::span and std::mdspan
In C++20 and C++23, std::span and std::mdspan were introduced, which can be understood as a type of view or slice similar to that in Go language. While this understanding is not entirely precise, it makes it easier for everyone to accept, serving as a compromise. As a multidimensional array view, std::mdspan has been significantly enhanced in C++26. Upon reflection, it becomes clear that both parallel computing and high-performance computing (HPC) often involve operations on various matrices and vectors, and multidimensional array views naturally have advantages in this regard.
2. Description of std::mdspan
C++26 introduces several key features to std::mdspan:1. Dimension DefinitionSupports defining fixed dimensions, dynamic dimensions, and mixed dimensions, which is very useful in parallel programming such as CUDA.2. Layout StrategiesTo optimize and improve memory efficiency, four types of strategies are supported: layout_right (default), layout_left, layout_stride, and layout_right_padded. layout_right supports row-major memory order while layout_left supports column-major memory order. The former is more suitable for image and mathematical computations, while the latter is better for BLAS (Basic Linear Algebra Subprograms) and LAPACK (Linear Algebra PACKage). layout_right_padded supports aligned row-major memory order, which is more suitable for SIMD optimization. layout_stride is for custom cases, allowing users to define and apply their own strategies in specific situations.3. AccessorsC++26 provides std::aligned_accessor for more convenient access to the data.4. SubviewsC++26 adds management for std::submdspan subviews, which are similar to slices. The advantage of subviews is that they allow for extensive data reuse without the need for constant copying operations.
3. Applications of std::mdspan
Based on the analysis of std::mdspan, let’s look at how to apply it:
1. Basic Application
// Dimension Definition
// Fixed Dimension (2x3)
using M1 = mdspan<float, extents<2, 3>>;
// Dynamic Dimension (NxM)
using dM1 = mdspan<int, dextents< 4>>; // Equivalent to mdspan<int, extents<dynamic_extent, dynamic_extent, dynamic_extent, dynamic_extent>>;
// Mixed Dimension (4xM)
using mM1 = mdspan<double, extents<4, dynamic_extent>>;
// Accessor
void compute_with_aligned(
std::mdspan<float, std::dims<2>, std::layout_left> matrix)
{
const std::size_t byte_alignment = 4 * alignof(float);
std::mdspan aligned_matrix{matrix.data_handle(), matrix.mapping(),
std::aligned_accessor<float, byte_alignment>{}};
// ... use aligned_matrix ...
}
// 64-byte alignment (AVX512)
alignas(64) float data[1024];
mdspan<const float, extents<16, 64>> aligned_view(data);
// Memory Layout
// BLAS-compatible column-major view
mdspan<double, dextents<2>, layout_left> bv(A.data(), m, n);
2. SubviewsThe following example demonstrates a function zero_surface that sets all elements on the surface of a three-dimensional shape to zero, given a rank-3 mdspan grid3d representing regularly spaced points in a rectangular prism. It achieves this by reusing a rank-2 mdspan function zero_2d:
template<class T, class E, class L, class A>
void zero_2d(mdspan<T,E,L,A> a) {
static_assert(a.rank() == 2);
for(int i=0; i<a.extent(0); i++)
for(int j=0; j<a.extent(1); j++)
a[i,j] = 0;
}
// zero out just the surface
template<class T, class E, class L, class A>
void zero_surface(mdspan<T,E,L,A> grid3d) {
static_assert(grid3d.rank() == 3);
zero_2d(submdspan(grid3d, 0, full_extent, full_extent));
zero_2d(submdspan(grid3d, full_extent, 0, full_extent));
zero_2d(submdspan(grid3d, full_extent, full_extent, 0));
zero_2d(submdspan(grid3d, grid3d.extent(0)-1, full_extent, full_extent));
zero_2d(submdspan(grid3d, full_extent, grid3d.extent(1)-1, full_extent));
zero_2d(submdspan(grid3d, full_extent, full_extent, grid3d.extent(2)-1));
}
Note: This example is taken from the proposal. More details will need to wait until the standard is finalized, and those interested can continue to follow up!
4. Conclusion
While reviewing other materials, I found that there is another proposal in C++26 for std::mdarray, but it has not been found on mainstream technical support pages, so it is uncertain whether it will ultimately be included. However, based on the development history of the standard, it is very likely to become part of the standard. Technology is human-centered, aimed at providing developers with a standard interface for flexible and diverse applications. This embodies the principle of “seeking flexibility within stability, and promoting stability through flexibility.”