多維array和多維視圖std::mdspan

多維數組

這個特性用于訪問多維數組,之前C++ operator[] 只支持訪問單個下標,無法訪問多維數組。
因此要訪問多維數組,以前的方式是:

  • 重載operator(),于是能夠以m(1, 2) 來訪問第1 行第2 個元素。但這種方式容易和函數調
    用產生混淆;
  • 重載operator[],并以std::initializer_list 作為參數,然后便能以m[{1, 2}] 來訪問元
    素。但這種方式看著別扭;
  • 鏈式鏈接operator[],然后就能夠以m[1][2] 來訪問元素。C語言二維數組的訪問方式;
  • 定義一個at() 成員,然后通過at(1, 2) 訪問元素。同樣不方便。

在C++23,我們終于可以通過m[1, 2] 這種方式來訪問多維數組。一個例子

template <class T, size_t R, size_t C>
struct matrix 
{T& operator[](const size_t r, const size_t c) noexcept {return data_[r * C + c];}const T& operator[](const size_t r, const size_t c) const noexcept {return data_[r * C + c];}private:
std::array<T, R * C> data_;
};int main() 
{matrix<int, 2, 2> m;m[0, 0] = 0;m[0, 1] = 1;m[1, 0] = 2;m[1, 1] = 3;for (auto i = 0; i < 2; ++i) {for (auto j = 0; j < 2; ++j) {std::cout << m[i, j] << ' ';}std::cout << std::endl;}
}

std::mdspan

std::mdspan(多維數組視圖)是 C++23 新增的非擁有多維數組的視圖,用于表示連續對象序列,允許靈活操作多維數據,支持動態維度。?這個連續對象序列可以是一個簡單的?C 數組、帶有大小的指針、std::arraystd::vector?或?std::stringmdspan?是一種輕量級的多維數組視圖,不持有數據,而是提供了對現有數據的多維訪問方式。它結合了指針和多維索引的優點,使得數據訪問更加高效和靈活。

在標頭?<mdspan>?定義

template<

? ??class?T,
? ??class?Extents,
? ??class?LayoutPolicy?=?std::layout_right,
? ??class?AccessorPolicy?=?std::default_accessor<T>

>?class?mdspan;

模板形參

T-元素類型;既不是抽象類也不是數組類型的完整對象類型。
Extents-指定維數及各維大小,均為編譯時已知。必須是?std::extents?的特化。
LayoutPolicy-指定如何將多維索引轉換為底層的一維索引(列優先三維數組、對稱三角二維矩陣等)。必須滿足布局映射策略?(LayoutMappingPolicy)?。
AccessorPolicy-指定如何將底層一維索引轉換為對 T 的引用。必須滿足?std::is_same_v<T,?typename?AccessorPolicy?::?element_type>?為?true?的約束條件。必須滿足訪問器策略?(AccessorPolicy)


由于 C++17 中的類模板參數推導(CTAD),編譯器通常可以自動從初始化器的類型推導出模板參數。

成員函數

(構造函數)

構造一個?mdspan
(公開成員函數)

operator=

給一個?mdspan?賦值
(公開成員函數)
元素訪問

operator[]

訪問指定多維索引處的元素
(公開成員函數)
觀察器

size

返回多維索引空間的大小
(公開成員函數)

empty

檢查索引空間大小是否為零
(公開成員函數)

stride

獲取沿指定維度的步長
(公開成員函數)

extents

獲取范圍(extent)對象
(公開成員函數)

data_handle

獲取指向底層一維序列的指針
(公開成員函數)

mapping

獲取映射(mapping)對象
(公開成員函數)

accessor

獲取訪問器策略對象
(公開成員函數)

is_unique

確定此 mdspan 的映射是否唯一(每個索引組合映射到不同的基礎元素)
(公開成員函數)

is_exhaustive

確定此 mdspan 的映射是否詳盡(exhaustive)(可以使用某些索引組合訪問每個底層元素)
(公開成員函數)

is_strided

確定此 mdspan 的映射是否跨步(在每個維度中,每次遞增索引都會跳過相同數量的基礎元素)
(公開成員函數)

is_always_unique

[靜態]

確定此 mdspan 的布局映射是否始終唯一(unique)
(公開靜態成員函數)

is_always_exhaustive

[靜態]

確定此 mdspan 的布局映射(layout mapping)是否總是詳盡的
(公開靜態成員函數)

is_always_strided

[靜態]

確定此 mdspan 的布局映射是否始終跨步(strided)
(公開靜態成員函數)

非成員函數

std::swap(std::mdspan)

(C++23)

針對 mdspan 特化的?std::swap?算法
(函數模板)
子視圖

submdspan

(C++26)

返回現存?mdspan?的子集上的視圖
(函數模板)

submdspan_extents

(C++26)

從現存 extents 和分片說明符創建新的 extents
(函數模板)

輔助類型和模板

extents

(C++23)

某秩多維索引空間的一個描述符
(類模板)

dextentsdims

(C++23)(C++26)

全動態?std::extents?的方便別名模板
(別名模板)

default_accessor

(C++23)

指示索引訪問?mdspan?元素的方式的類型
(類模板)

aligned_accessor

(C++26)

提供按對齊訪問?mdspan?成員的類型
(類模板)
布局映射策略

layout_left

(C++23)

列優先多維數組布局映射策略;最左邊的尺度具有步幅?1
(類)

layout_right

(C++23)

行優先多維數組布局映射策略;最右邊的尺度具有步幅?1
(類)

layout_stride

(C++23)

具有用戶自定義步長的布局映射策略
(類)

layout_left_padded

(C++26)

具有可大于或等于最左側尺度的填充跨步的列主序布局映射策略
(類)

layout_right_padded

(C++26)

具有可大于或等于最右側尺度的填充跨步的行主序布局映射策略
(類)
子視圖輔助項

full_extentfull_extent_t

(C++26)

切片說明符標簽,描述指定尺度的全部索引范圍。
(標簽)

strided_slice

(C++26)

切片說明符,表示一組按照偏移量、尺度和跨步三值指定的有規律分布的索引
(類模板)

submdspan_mapping_result

(C++26)

各?submdspan_mapping?重載的返回類型
(類模板)

示例 1:基本使用

#include<iostream>
#include <mdspan>int main() {// 一維連續存儲(模擬二維數組)int data[] = {1,2,3,4,5,6,7,8,9,10,11,12};// 創建 3x4 的二維視圖std::mdspan mat(data, 3, 4); // 訪問元素 [行][列]std::cout << mat[1][2]; // 輸出 7// 修改元素mat[2][3] = 42; // 修改第3行第4列的元素
}

示例 2:動態維度?

#include <mdspan>
#include <vector>int main() {std::vector<int> data(20); // 動態存儲// 創建 4x5 的動態視圖std::mdspan<int, std::dextents<2>> dyn_span(data.data(), 4, 5);dyn_span[3][4] = 100; // 最后一元素
}

3. 多維數組的布局策略

mdspan?允許指定內存布局,優化訪問模式:

  • 行優先(C風格)std::layout_right(默認)

  • 列優先(Fortran風格)std::layout_left

#include <mdspan>int main() {int data[12] = { /* ... */ };// 列優先的 3x4 視圖std::mdspan<int, std::extents<3,4>, std::layout_left> col_major(data);
}

4. 切片與子視圖

mdspan?支持通過切片操作獲取子視圖:

auto sub_view = std::submdspan(mat, 1, std::full_extent); // 獲取第2行所有列
std::cout << sub_view[2]; // 輸出原數組的 mat[1][2]

5. 結合算法使用

多維數組與標準庫算法協同工作:

#include <algorithm>
#include <mdspan>int main() 
{int data[3][4] = { /* ... */ };std::mdspan mat(data);// 遍歷所有元素std::for_each(mat.data_handle(), mat.data_handle() + mat.size(), [](int& x) { x *= 2; });
}

5. 布局策略

std::mdspan?允許您指定用于訪問底層內存的布局策略。默認情況下,使用?std::layout_right(C、C++ 或 Python 風格),但您也可以指定?std::layout_left(Fortran?或 MATLAB 風格)。

使用布局策略std::mdspanstd::layout_right遍歷兩個std::layout_left可以看出差異。

#include <mdspan>
#include <iostream>
#include <vector>int main() 
{std::vector myVec{1, 2, 3, 4, 5, 6, 7, 8};std::mdspan<int, std::extents<std::size_t,      // (1)std::dynamic_extent, std::dynamic_extent>, std::layout_right> m{myVec.data(), 4, 2};std::cout << "m.rank(): " << m.rank() << '\n';for (std::size_t i = 0; i < m.extent(0); ++i) {for (std::size_t j = 0; j < m.extent(1); ++j) {std::cout << m[i, j] << ' ';  }std::cout << '\n';}std::cout << '\n';std::mdspan<int, std::extents<std::size_t,     // (2)std::dynamic_extent, std::dynamic_extent>, std::layout_left> m2{myVec.data(), 4, 2};std::cout << "m2.rank(): " << m2.rank() << '\n';for (std::size_t i = 0; i < m2.extent(0); ++i) {for (std::size_t j = 0; j < m2.extent(1); ++j) {std::cout << m2[i, j] << ' ';  }std::cout << '\n';}}

6. 性能與注意事項

  • 連續存儲mdspan?不管理內存,需確保底層數據連續。

  • 邊界檢查:默認無越界檢查,可通過自定義策略添加。

  • 靈活性:適用于科學計算、圖像處理等需要多維數據的場景。


總結

  • 傳統多維數組:適合靜態、編譯時已知維度的場景。

  • std::mdspan:提供動態維度、靈活布局和高效訪問,是 C++23 處理多維數據的現代方式。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/73936.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/73936.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/73936.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python標準庫之os模塊常用方法

一、os模塊簡介 os模塊是Python標準庫中與操作系統交互的一個重要模塊。它提供了非常豐富的方法來處理文件、目錄以及與操作系統相關的操作&#xff0c;讓我們可以編寫跨平臺的代碼&#xff0c;無論是在Windows、Linux還是macOS系統上都能運行。 二、文件和目錄操作 獲取當前…

利用AI讓數據可視化

1. 從問卷星上下載一份答題結果。 序號用戶ID提交答卷時間所用時間來源來源詳情來自IP總分1、《中華人民共和國電子商務法》正式實施的時間是&#xff08;&#xff09;。2、&#xff08;&#xff09;可以判斷企業在行業中所處的地位。3、&#xff08;&#xff09;是指店鋪內有…

K8S學習之基礎三十五:k8s之Prometheus部署模式

Prometheus 有多種部署模式&#xff0c;適用于不同的場景和需求。以下是幾種常見的部署模式&#xff1a; 1. 單節點部署 這是最簡單的部署模式&#xff0c;適用于小型環境或測試環境。 特點&#xff1a; 單個 Prometheus 實例負責所有的數據采集、存儲和查詢。配置簡單&…

【第14節】windows sdk編程:進程與線程介紹

目錄 一、進程與線程概述 1.1 進程查看 1.2 何為進程 1.3 進程的創建 1.4 進程創建實例 1.5 線程查看 1.6 何為線程 1.7 線程的創建 1.8 線程函數 1.9 線程實例 二、內核對象 2.1 何為內核對象 2.2 內核對象的公共特點 2.3 內核對象句柄 2.4 內核對象的跨進程訪…

Python簡單爬蟲實踐案例

學習目標 能夠知道Web開發流程 能夠掌握FastAPI實現訪問多個指定網頁 知道通過requests模塊爬取圖片 知道通過requests模塊爬取GDP數據 能夠用pyecharts實現餅圖 能夠知道logging日志的使用 一、基于FastAPI之Web站點開發 1、基于FastAPI搭建Web服務器 # 導入FastAPI模…

uniapp工程中解析markdown文件

在uniapp中如何導入markdown文件&#xff0c;同時在頁面中解析成html&#xff0c;請參考以下配置&#xff1a; 1. 安裝以下3個依賴包 npm install marked highlight.js vite-plugin-markdown 2. 創建vite.config.js配置文件 // vite.config.js import { defineConfig } fro…

sass介紹

1、Sass簡介 Sass 是一種 CSS 的預編譯語言。它提供了 變量&#xff08;variables&#xff09;、嵌套&#xff08;nested rules&#xff09;、 混合&#xff08;mixins&#xff09;、 函數&#xff08;functions&#xff09;等功能&#xff0c;并且完全兼容 CSS 語法。Sass 能…

[JavaScript]如何利用作用域塊避免閉包內存泄漏?

出自《你不知道的JavaScript》上卷 以下是本書給出的反例: function process (data) {...} var bigdata{...} process(bigdata); var btn document.getElementById(x); btn.addEventListener(click, function click{...});click會被回調在其他位置, 在addEventListener函數內…

leetcode hot100(五)

11. 盛最多水的容器 給定一個長度為 n 的整數數組 height 。有 n 條垂線&#xff0c;第 i 條線的兩個端點是 (i, 0) 和 (i, height[i]) 。 找出其中的兩條線&#xff0c;使得它們與 x 軸共同構成的容器可以容納最多的水。 返回容器可以儲存的最大水量。 說明&#xff1a;你…

Unity 云渲染本地部署方案

Unity Render Streaming 云渲染環境搭建 0.安裝 Unity Render Streaming 實現原理: 服務器與客戶端實現功能包括: 詳細內容見官方文檔&#xff1a; 官方文檔: https://docs.unity3d.com/Packages/com.unity.renderstreaming3.1/manual/tutorial.html Unity 流送云渲染介紹: …

洛谷 P3986 斐波那契數列

P3986 斐波那契數列 題目描述 定義一個數列&#xff1a; f ( 0 ) a , f ( 1 ) b , f ( n ) f ( n ? 1 ) f ( n ? 2 ) f(0) a, f(1) b, f(n) f(n - 1) f(n - 2) f(0)a,f(1)b,f(n)f(n?1)f(n?2) 其中 a, b 均為正整數&#xff0c;n ≥ 2。 問有多少種 (a, b)&…

【java面型對象進階】------繼承實例

繼承結構下的標準Javabean 代碼如下&#xff1a; package demo10;//定義員工父類 public class Employee {private String id;private String name;private double salary;//構造方法public Employee(){}public Employee(String id,String name,double salary){this.idid;thi…

Vitis 2024.1 無法正常編譯custom ip的bug(因為Makefile里的wildcard)

現象&#xff1a;如果在vivado中&#xff0c;添加了自己的custom IP&#xff0c;比如AXI4 IP&#xff0c;那么在Vitis&#xff08;2024.1&#xff09;編譯導出的原本的.xsa的時候&#xff0c;會構建build失敗。報錯代碼是&#xff1a; "Compiling blank_test_ip..."…

【圖論】并查集的學習和使用

目錄 并查集是什么&#xff1f; 舉個例子 組成 父親數組&#xff1a; find函數&#xff1a; union函數&#xff1a; 代碼實現&#xff1a; fa[] 初始化code: find code&#xff1a; 遞歸實現: 非遞歸實現: union code : 畫圖模擬&#xff1a; 路徑壓縮&#xff1a…

Java使用FFmpegFrameGrabber進行視頻拆幀,結合Thumbnails壓縮圖片保存到文件夾

引入依賴 <dependency><groupId>net.coobird</groupId><artifactId>thumbnailator</artifactId><version>0.4.17</version></dependency><dependency><groupId>org.bytedeco</groupId><artifactId>ja…

mysql與redis的日志策略

MySQL 和 Redis 在日志記錄方面采用了不同的策略&#xff0c;分別對應寫前日志&#xff08;Write-Ahead Logging, WAL&#xff09;和寫后日志&#xff08;Write-After Logging&#xff09;。以下是它們的詳細說明&#xff1a; 1. MySQL&#xff1a;寫前日志&#xff08;Write-A…

nacos安裝,服務注冊,服務發現,遠程調用3個方法

安裝 點版本下載頁面 服務注冊 每個微服務都配置nacos的地址&#xff0c;都要知道 服務發現 2個是知道了解 遠程調用基本實現 遠程調用方法2&#xff0c;負載均衡API測試 遠程調用方法3&#xff0c;注解 負載均衡的遠程調用&#xff0c; 總結 面試題

Ubuntu Qt: no service found for - “org.qt-project.qt.mediaplayer“

1、前言 在一次項目過程中&#xff0c;因項目需求&#xff0c;需要將windows開發的Qt項目遷移到ubuntu系統中&#xff0c;且在某個功能項中需要播放音頻&#xff0c;在windows系統中能夠正常運行&#xff0c;但在ubuntu系統中卻顯示defaultServiceProvider::requestService(): …

Blender制作次表面材質

效果: 主要用沃羅諾伊紋理做出云絮感 然后EV開啟次表面設置

用 pytorch 從零開始創建大語言模型(四):從零開始實現一個用于生成文本的GPT模型

從零開始創建大語言模型&#xff08;Python/pytorch &#xff09;&#xff08;四&#xff09;&#xff1a;從零開始實現一個用于生成文本的GPT模型 4 從零開始實現一個用于生成文本的GPT模型4.1 編寫 L L M LLM LLM架構4.2 使用層歸一化對激活值進行標準化4.3 使用GELU激活函數…