c++c++-faqstd-spanmdspan

What is an mdspan, and what is it used for?


Over the past year or so I've noticed a few C++-related answers on StackOverflow refer to mdspan's - but I've never actually seen these in C++ code. I tried looking for them in my C++ compiler's standard library directory and in the C++ coding guidelines - but couldn't find them. I did find std::span's; I'm guessing they're related - but how? And what does this addition of "md" stand for?

Please explain what this mysterious entity is about, and when I might want to use it.


Solution

  • TL;DR: mdspan is an extension of std::span for multiple dimensions - with a lot of (unavoidable) flexibile configurability w.r.t. memory layout and modes of access.


    Before you read this answer, you should make sure you're clear on what a span is and what it's used for. Now that that's out of the way: Since mdspan's can be rather complex beasts (typically ~7x or more source code as an std::span implementation), we'll start with a simplified description, and keep the advanced capabilities for further below.

    "What is it?" (simple version)

    An mdspan<T> is:

    1. Literally, a "multi-dimensional span" (of type-T elements).
    2. A generalization of std::span<T>, from a uni-dimensional/linear sequence of elements to multiple dimensions.
    3. A non-owning view of a contiguous sequence of elements of type T in memory, interpreted as a multi-dimensional array.
    4. Basically just a struct { T * ptr; size_type extents[d]; } with some convenience methods (for d dimensions determined at run-time).

    Illustration of mdspan-interpreted layout

    If we have:

    std::vector v = {1,2,3,4,5,6,7,8,9,10,11,12};
    

    we can view the data of v as a 1D array of 12 elements, similar to its original definition:

    auto sp1 = std::span(v.data(), 12);
    auto mdsp1 = std::mdspan(v.data(), 12);
    

    or a 2D array of extents 2 x 6:

    auto mdsp2 = std::mdspan(v.data(), 2, 6);
    // (  1,  2,  3,  4,  5,  6 ),
    // (  7,  8,  9, 10, 11, 12 )
    

    or a 3D array 2 x 3 x 2:

    auto ms3 = std::mdspan(v.data(), 2, 3, 2);
    // ( ( 1,  2 ), ( 3,  4 ), (  5,  6 ) ),
    // ( ( 7,  8 ), ( 9, 10 ), ( 11, 12 ) )
    

    and we could also consider it as a 3 x 2 x 2 or 2 x 2 x 3 array, or 3 x 4 and so on.

    "When should I use it?"

    Standardization status

    std::mdspan has been standardized, and is part of C++23 (while std::span was already available in C++20). However, not all relevant facilities were standardized, e.g. the ability to take a sub-mdspan of an existing md-span will likely only enter the standard in C++26.

    Even before C++23, you could already use a reference implementation, which comes from the US' Sandia National Laboratory's "Kokkos performance portability ecosystem".

    "What are those 'extra capabilities' which mdspan offers?"

    An mdspan actually has 4 template parameters, not just the element type and the extents:

    template <
        class T,
        class Extents,
        class LayoutPolicy = layout_right,
        class AccessorPolicy = default_accessor<ElementType>
    >
    class mdspan;
    

    This answer is already rather long, so we won't give the full details, but:

    Further reading

    (some examples were adapted from these sources.)