Search code examples
c++c++23mdspan

Why I can not construct mdspan from 2D C array?


Following code does not compile:

void fn(std::span<int> ) {}

int main() {
    int  arr[4][5]{};
    fn(arr[0]);
    std::mdspan msp(arr); 
}

This is because std::mdspan is not constructible from a 2D C array. From what I see, this behavior was intentionally designed, as the deduction guide specifies the following:

requires(std::is_array_v<CArray> && std::rank_v<CArray> == 1)

However, I find this somewhat counterintuitive. Sometimes, I have a specific-size 2D array and would like to pass it to a generic function that operates on any 2D mdspan. It seems natural to me that this should be supported.


Solution

  • I had a quick look at the proposal but didn't find anything. My best guess is that N-dimensional arrays in C/C++ are just inherently ugly.

    Let's say you have a flat int arr[4*5];. You can construct a 2D span from pointer &arr[0] (aka just arr) and two dimensions.

    Now if you try create the same 2D span from int arr[4][5];, what pointer do you pass and store?

    • If you pass &arr[0][0] (aka arr[0]), you can only legally access arr[0][i] and not the rest of arr[j][i].

      While I doubt compilers will choke on this at runtime, I believe they do validate this in constexpr contexts.

    • Passing &arr[0] (aka just arr) fixes that, but that's a different pointer type.

      std::mdspan is flexible enough to allow customizing which pointer type is stored (via a custom accessor), so do we cook up a custom accessor for N-dim arrays?

      While I think it could be possible, accessors operate on 1D indices, so you would need to convert them back to N-dim indices to index the pointer, and so on.

    A better solution would be to fix the language so that &arr[0][0] can be used to access the entire arr[j][i], since people are doing this all the time anyway, and then the support can be added to std::mdspan without the accessor nonsense.