1. Vấn đề nó giải quyết
Cùng tọa độ logic có thể ánh xạ vào bộ nhớ theo thứ tự khác, và truy cập phần tử có thể cần policy tùy biến. mdspan tách extents, layout mapping và accessor để tùy biến không thêm chi phí.
2. Kiến thức cần có
Ngày 50: ownership và extents của mdspan.
Ngày 4: kiểu generic dựa trên policy.
3. Ý tưởng cốt lõi
Extents định nghĩa lưới, layout mapping đổi tọa độ thành offset, còn accessor biến handle cộng offset thành tham chiếu hoặc giá trị được lộ ra. Hãy xác định giá trị đang được biến đổi rồi kiểm tra kiểu, lifetime hoặc quyền sở hữu kết quả. Bật C++23 chưa chắc thư viện đã triển khai đủ, vì vậy cần kiểm tra feature-test macro liên quan.
4. Cú pháp tối thiểu
std::mdspan<T, Extents, std::layout_left, Accessor> view(data);5. Cách nó hoạt động
Ví dụ tạo biểu thức hoặc đối tượng nhỏ nhất cho Layout, mapping và accessor của
mdspan.Chương trình so sánh offset layout và dùng read accessor nhỏ khi mdspan được triển khai.
Cuối cùng, nó in hoặc kiểm tra offset khác nhau cho cùng tọa độ và giá trị đã qua accessor để dễ đối chiếu.
6. Lỗi thường gặp
Dùng layout không khớp storage bên ngoài sẽ âm thầm đọc sai phần tử; custom accessor trả proxy treo hoặc vi phạm hợp đồng offset làm hỏng view.
Không kiểm tra feature-test macro có thể chọn nhánh mã thư viện hiện tại chưa hỗ trợ.
7. Khi nào nên dùng
Nên dùng khi tương tác với bộ nhớ row-major, column-major, strided, device hoặc truy cập đặc biệt.
Tránh dùng khi tạo policy tùy biến khi
layout_rightvàdefault_accessorđã khớp storage.
8. Ví dụ đơn giản
Mảng khoa học column-major dùng layout_left, còn checking accessor đưa giá trị ra qua policy đọc có kiểm soát. Chương trình dùng dữ liệu cố định để output dễ kiểm tra.
Mã mẫu hoàn chỉnh
Tệp mã nguồn
cpp23/51_mdspan_layouts_mappings_accessors/main.cpp
#include <array>
#include <cstddef>
#include <iostream>
#include <version>
#if __has_include(<mdspan>)
#include <mdspan>
#endif
#if defined(__cpp_lib_mdspan)
struct DoubleAccessor {
using offset_policy = DoubleAccessor;
using element_type = const int;
using reference = int;
using data_handle_type = const int*;
constexpr reference access(data_handle_type data,
std::size_t index) const noexcept {
return data[index] * 2;
}
constexpr data_handle_type offset(data_handle_type data,
std::size_t index) const noexcept {
return data + index;
}
};
#endif
int main() {
#if defined(__cpp_lib_mdspan)
using Shape = std::extents<std::size_t, 2, 3>;
using Left = std::layout_left::mapping<Shape>;
using Right = std::layout_right::mapping<Shape>;
using View = std::mdspan<const int, Shape,
std::layout_left, DoubleAccessor>;
std::array data{1, 2, 3, 4, 5, 6};
View view(data.data(), Left{}, DoubleAccessor{});
std::cout << "left offset=" << Left{}(1, 0)
<< " right offset=" << Right{}(1, 0)
<< " value=" << view[1, 2] << '\n';
#else
std::cout << "mdspan policies unavailable\n";
#endif
}
9. Điều cần nhớ
Tách quy tắc chuẩn khỏi mức hỗ trợ thực tế.
Làm rõ lifetime, ownership và kiểu suy luận.
Ưu tiên cú pháp ngắn, đúng ý định.
Guard tính năng chưa được hỗ trợ đồng đều.
10. Câu hỏi tự kiểm tra
Dễ — Cú pháp ngắn nhất ở Phần 4 là gì và nhiệm vụ chính của nó là gì?
Trung bình — Đọc chương trình mẫu: giá trị, kiểu hoặc nhánh nào được quan sát, và vì sao?
Khó — Với matrix
2 × 3,layout_leftvàlayout_rightánh xạ tọa độ(1, 0)thế nào, và mỗi layout ngụ ý thứ tự storage nào?