libcu++ 2.1.0 включает реализацию mdspan для nvcc для c++14 и более поздних версий. Я попытался реализовать пример кода mdspan из cppreference (https://en.cppreference.com/w/cpp/container/mdspan) с nvcc 12.0 и libcu++ 2.1.0.
Я заметил две проблемы.
Во-первых, я не могу построить mdspan так же, как в примере.
ни один экземпляр конструктора "mdspan" не соответствует списку аргументов типы аргументов: (int *, int, int)
Во-вторых, доступ к mdspan через operator[] не компилируется
ошибка: ни один оператор "[]" не соответствует этим операндам типы операндов: cuda::std::__4::mdspan<int, cuda::std::__4::extents<std::size_t, 2UL, 3UL, 2UL>, cuda::std::__4::layout_right , cuda::std::__4::default_accessor> [ std::size_t ]
1. Как указать в конструкторе экстент, который неизвестен во время компиляции?
2. Как получить доступ к данным mdspan?
Ниже приведен мой код, который не компилируется с помощью nvcc -Ilibcudacxx-2.1.0/include/ -std=c++17 main.cu -o main.
#include <cstddef>
#include <vector>
#include <cstdio>
#include <cuda/std/mdspan>
int main()
{
std::vector v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
//error: no instance of constructor "mdspan" matches the argument list. argument types are: (int *, int, int)
//auto ms2 = cuda::std::mdspan(v.data(), 2, 6);
//auto ms3 = cuda::std::mdspan(v.data(), 2, 3, 2);
//no compilation error with compile-time extents
cuda::std::mdspan<int, cuda::std::extents<std::size_t, 2,6>> ms2(v.data());
cuda::std::mdspan<int, cuda::std::extents<std::size_t, 2,3,2>> ms3(v.data());
// write data using 2D view
for (std::size_t i = 0; i != ms2.extent(0); i++)
for (std::size_t j = 0; j != ms2.extent(1); j++)
//no operator "[]" matches these operands. operand types are: cuda::std::__4::mdspan<int, cuda::std::__4::extents<std::size_t, 2UL, 6UL>, cuda::std::__4::layout_right, cuda::std::__4::default_accessor<int>> [ std::size_t ]
ms2[i, j] = i * 1000 + j;
// read back using 3D view
for (std::size_t i = 0; i != ms3.extent(0); i++)
{
printf("slice @ i = %lu\n", i);
for (std::size_t j = 0; j != ms3.extent(1); j++)
{
for (std::size_t k = 0; k != ms3.extent(2); k++)
printf("%d ", ms3[i, j, k]);
printf("\n");
}
}
}





Реализация mdspan в libcu++ основана на эталонной реализации Kokkos, которая имеет некоторые предостережения в файле readme:
Эта реализация полностью соответствует версии
mdspan, за которую проголосовали в проекте стандарта C++23 в июле 2022 года. Если не в режиме С++ 23, реализация отличается от предложения следующим образом:С++ 20
- реализует
operator()неoperator[]
- обратите внимание, что вы можете контролировать, какой оператор доступен с определением
MDSPAN_USE_BRACKET_OPERATOR=[0,1]иMDSPAN_USE_PAREN_OPERATOR=[0,1]независимо от того, обнаружена ли поддержка многомерного нижнего индекса.С++ 17
- mdspan имеет конструктор по умолчанию даже в тех случаях, когда он не должен (т. е. все статические экстенты и конструируемое сопоставление/доступ по умолчанию)
- условная явная разметка отсутствует, что делает некоторые конструкторы неявными
- в частности, вы можете неявно преобразовать динамический экстент в статический экстент, чего нельзя сделать в режиме С++ 20.
- существует ограничение на
layout_left::mapping::stride(),layout_right::mapping::stride()иlayout_stride::mapping::stride(), чтоextents_type::rank() > 0естьtrue, которое не реализовано в C++17 или C++14.С++ 14
- руководства по дедукции не существует
- submdspan (P2630) недоступен — более ранний вариант submdspan доступен до версии 0.5 в режиме C++14.
- бенчмарки недоступны (нужны submdspan)
Причина использования эталонной реализации с использованием operator() вместо operator[] (см. раздел «C++20» выше) заключается в том, что operator[] с несколькими аргументами является функцией C++23, поэтому ее нельзя перенести на более ранние версии C++.
Конструктор, который используется в примере, реализован для C++17 (в C++14 нет необходимых руководств CTAD*/deduction), или, по крайней мере, для него есть тест . CTAD может быть отключен для некоторых (хост-) компиляторов/версий , но есть альтернативный способ указания динамических экстентов без CTAD:
constexpr auto dyn = cuda::std::dynamic_extent;
int main() {
...
using ext_t = cuda::std::extents<int, dyn, dyn>;
cuda::std::mdspan<int, ext_t> ms2{ v.data(), ext_t{2, 6} };
...
}
*CTAD: вывод аргумента шаблона класса