這系列應該是最後一篇了。在講完了基本的使用、還有一些其他的函式,最後這邊來講一下要怎麼針對自己定義的型別、或是官方沒支援的型別做處理、讓他可以用在 std::format 上。
不過 Heresy 這邊也必須講一下,Heresy 自己沒有找到針對這部分比較完整的說明、範例,所以其實這裡的東西大多是網路上找了很多範例、自己拼湊出來的,其實也不太能保證都正確,只能說在 MSVC 上可以正常運作。
如果哪裡有寫錯的話,也希望可以告知一下。
C++ 相關
這系列應該是最後一篇了。在講完了基本的使用、還有一些其他的函式,最後這邊來講一下要怎麼針對自己定義的型別、或是官方沒支援的型別做處理、讓他可以用在 std::format 上。
不過 Heresy 這邊也必須講一下,Heresy 自己沒有找到針對這部分比較完整的說明、範例,所以其實這裡的東西大多是網路上找了很多範例、自己拼湊出來的,其實也不太能保證都正確,只能說在 MSVC 上可以正常運作。
如果哪裡有寫錯的話,也希望可以告知一下。
延續前面的 part 1,這邊繼續來講一些 C++20 std::format 的其他東西吧~
這邊,主要是來講一下他提供的一些其他函式。
微軟在去年底正式推出了第一款原生 64 位元的 Visual Studio 2022(17.0)後,其實已經有一次比較大的更新、17.1 了~
不過比較可惜的是,Heresy 這邊的程式因為踩到 Lambda + OpenMP 的問題,所以一直沒能把主要的建置環境切換到 Visual Studio 2022…
而現在,微軟終於推出解決該問題的 Visual Studio 2022 17.2 了!
官方的介紹是《Visual Studio 2022 17.2 is now available!》,比較完整個變化則可以參考官方的 Release Note。
由於 C++ 本身的 stream 要拿來做文字的格式化,使用上很麻煩,所以 Heresy 這邊之前都是用 Boost C++ Libraries 的 boost format 來做。
本來是期望 boost format 可以整到 std 裡面變成標準,不過很遺憾的是,C++ 20 雖然加入了 format 函式庫,但是卻不是基於 Boost format、而是基於 {fmt} 這個函式庫(官網、GitHub)的版本。
考慮到個人是希望盡量使用標準函式庫,這邊就來稍微整理一下 C++20 的 format 吧~
首先,這部分的文件可以參考:https://en.cppreference.com/w/cpp/utility/format
微軟的 Visual C++ 這幾年雖然對於 C++ 新的標準支援的算是相當積極,但是對於 OpenMP 的支援一直以來都很糟糕,儘管官方標準已經更新到 OpenMP 5.2 了,但是直到推出 Visual Studio 2019 的時候,卻還停留在 OpenMP 2.0 的超古老版本…
直到之前在 Visual Studio 2019 16.9 的時候,才終於試著開始幫 Visual C++ 的 OpenMP 加上新功能;當時主要的改進,是加入了 OpenMP 對於 SIMD 的支援,另外也開始試著要將 OpenMP 的實作切換到 LLVM 的版本。
而這次微軟又發布了《OpenMP Task Support for C++ in Visual Studio》,在最新的 Visual Studio 2022 17.2(還在預覽階段)中,在使用 LLVM OpenMP(加上 -openmp:llvm)的情況下,終於支援 OpenMP 3 的 task 這個 directive 了!
std::span 是 C++20 加入的一個新的類別(文件),他的基本概念是「對連續資料做處理的一個觀察者(view)」;由於只是「觀察者」,所以他並不具有所有權,某種意義上,可以看成類似一組連續資料的局部參考。
在最簡單的用法上,個人覺得它可以用來處理傳統陣列的傳遞;某種意義上算是做個封包、包裝成 STL 的容器的形式。下面是一個簡單的範例:
#include <iostream> #include <span> #include <algorithm> int main() { int aData[]{ 5, 4, 3, 2, 1 }; std::span sData(aData); std::cout << sData.size() << "\n"; // 5 std::ranges::sort(sData); }
在寫多執行序的程式的時候,如果有需要把文字輸出到 console 的時候,應該都有機會碰到不同執行序的文字交錯出現、導致難以閱讀的問題。
像下面就是一個簡單的例子:
#include <iostream> #include <thread> #include <vector> void test(const int idx) { for (int i = 0; i < 3; ++i) std::cout << "Thread " << idx << " step " << i << std::endl; } int main() { std::vector<std::thread> poolThread; for (int i = 0; i < 3; ++i) poolThread.emplace_back([i]() { test(i); }); for (auto& rThread : poolThread) rThread.join(); }
C++ 的標準函式庫雖然一直以來都有提供 <algorithm> 這個函式庫(參考),可以來做某些處理;而裡面其實也有像是 std::for_each()(參考)或 std::for_each_n()(參考)這類的函式、可以用來掃完整個陣列。
但是由於這些演算法大多是針對 iterator 來進行操作,在很多需要使用索引值(index)來存取周圍的資料時,會變得相對麻煩;也因此,其實 Heresy 這邊大多會使用傳統的 for 迴圈、或是 C++11 的 range-base for-loop 來寫,而很少會去用 std::for_each()。
也因此,當 C++17 開始正式針對部分也算法提供平行化的能力的時候(參考),雖然高興了一陣子,但是卻也發現有點難以使用…