透過 counting_iterator 讓 std::for_each_n 用索引值來操作

C++ 的標準函式庫雖然一直以來都有提供 <algorithm> 這個函式庫(參考),可以來做某些處理;而裡面其實也有像是 std::for_each()參考)或 std::for_each_n()參考)這類的函式、可以用來掃完整個陣列。

但是由於這些演算法大多是針對 iterator 來進行操作,在很多需要使用索引值(index)來存取周圍的資料時,會變得相對麻煩;也因此,其實 Heresy 這邊大多會使用傳統的 for 迴圈、或是 C++11 的 range-base for-loop 來寫,而很少會去用 std::for_each()

也因此,當 C++17 開始正式針對部分也算法提供平行化的能力的時候(參考),雖然高興了一陣子,但是卻也發現有點難以使用…

閱讀更多»

C++ 程式執行的順序

不知道一般人覺得下面這段 C++ 程式碼,執行會是什麼結果?

int i = 0;
std::cout << ++i << "/" << ++i << "/" << ++i << std::endl;

很直覺地,感覺應該會是「1/2/3」吧?

但是實際上,如果使用 g++ 6 以前的版本、或是 Visual Studio 2019 的話,應該會很訝異地發現,結果是「3/3/3」!

閱讀更多»

C++ 17/20 的一些數值函式庫

這篇是延續之前的《C++11 的一些數值函式庫》,繼續來整理 C++17C++20 在數值函式庫上的變化。

首先,在 <numeric> 這個 header 裡面(參考),又加入了很多 template 函式可以使用,其中也包含了 gcd(對大公因數)、lcm(最小公倍數)、inner_product(內積)等等;雖然不能說沒用,但是老實說,有需要的人大概都已經有自己的方案了吧…

另外,這次也還有支援平行化reduce(),以及在平行化演算法裡面很常見的 inclusive_scan()exclusive_scan() 可以使用。

閱讀更多»

更多元的函式回傳型別:optional 與 outcome

一般當在設計函式介面的時候,都會直接把結果回傳出來;比如說:

int compute(const int input)
{
  return 100 / input;
}

這樣的設計非常直覺,但是像以上面的例子來說,如果 input 是 0 的時候,這個函式就會產生例外狀況(exception)了。

而如果我們想要用 exception 以外的形式,來處理這類的錯誤的話,通常就需要修改函式的介面,讓他可以回傳執行的狀況。

閱讀更多»

C++14 與 C++17 Lambda Expression 的改變

在很久以前,Heresy 就曾經曾對 C++11(當時還叫做 C++0x)的新語法、Lambda Experssion 寫過簡單的介紹、《C++0x:Lambda expression》了~

由於 lambda 這種匿名函式再搭配需要使用 function object 的時候,會是一個相當方便的東西,所以 Heresy 也常常在使用。

而在 C++11 引進後,其實在後面的 C++14C++17 中,也都有針對 lambda 再做一些改進;雖然之前其實也有簡單提過,不過這邊就在整理一下,這兩次改版中,Heresy 個人覺得比較用的到的變化吧~

閱讀更多»

C++17 新的數字、字串轉換函式庫:std::from_chars

在 C++ 裡面,其實已經有不少在字串與數字間轉換的方法了,像是 sprintf、sscanf、atol、strtol、stringstream、to_string 等等…

而在 Boost C++ Libraries 裡面,為了各種原因,也有另外提供 lexical_castConvert 等函式庫,讓使用者可以更方便地進行文字和數字間的轉換。

C++17 裡面,又有另一個標準的選擇了!那就是 std::from_chars()參考)。

為什麼在已經有這麼多方法的情況下,還要再多弄一個出來呢?基本上,std::from_chars() 是一個相對低接、可以提供最好的效能的函式;或許使用上沒那麼便利,但是適用於非常在乎效能的時候。

閱讀更多»

C++ 資料成員初始化 @ C++11/17(inline variable)

在 Heresy 來看,C++ 類別(或結構)的資料成員(data member)的初始化,其實一直很麻煩…因為要初始化他的值,不能像一般變數一樣,在宣告的同時就同時定義,變成要初始化的話,會變成一定要去定義類別的建構子才行…

以前的寫法,基本上就是:

class CTest
{
public:
	int m_iValue1;
 
public:
	CTest() : m_iValue1(128)  {}
};

這樣寫法一個比較麻煩的地方,就是如果有好幾個建構子的話,那每個建構子都給各自去給初始化的值。

閱讀更多»

C++ 的一些 attribute

C++ 的 attribute(參考)是在 C++11 新加入的東西。他基本上算是在程式碼裡面,加上特別的輔助說明,給編譯器看,讓編譯器可以在編譯時針對這些屬性來做處理。

這樣的功能其實以前編譯器大多是有自己定義。像 gcc 是用 __attribute__參考)、MSVC 則是有 __declspec參考,現在則算是終於有個統一的標準了。

目前 C++ attribute 的寫法滿特別的,他是直接用兩組中括號夾住、寫成 [[…]] 這樣的形式。而到 C++20 為止,也訂了超過十個 attribute 了(到還沒定案的 C++20)(除了標準定義的部分,編譯器也還有可以有自己定義的東西);在大部分的狀況下,他們主要的功能大概就是避免編譯器產生不必要的警告、增加程式碼的可讀性,以及讓編譯器更好最佳化吧~

其中有的個人覺得還算滿有用的,所以這邊就大概紀錄一下。

閱讀更多»

在 header 檔使用 constexpr 定義全域變數

這邊是看到《Quick Q: use of constexpr in header file》這篇文章,覺得還滿實用的,所以來記錄一下;他基本上是有人在 StackOverflow 上有人提出這個問題(頁面)後,相關的討論。

首先,「constexpr」這個關鍵字,是在 C++11 加入的東西(參考);它的用處,是將變數或函式宣告為可以在編譯階段(compile time)就可以計算出他的值。

透過這個關鍵字,除了可以讓編譯器在編譯時就針對這些東西最佳化外,更有可能讓寫出更多在編譯階段展開的語法。像是 C++17 的「if constexpr」(參考),也可以在撰寫某些程式時、更為方便。

而在某些地方,也可以看到有人建議用 constexpr 來取代 #define,來作為更好的變數定義(至少會是 type-safe 的)。

而這邊的問題是:

可以在 header 檔中,使用 constexpr 來定義變數嗎?當多個 .cpp 檔去 include 他的時候,會不會產生多個實體、或是造成變數重定義的問題?

閱讀更多»

C++17 更通用的 union:variant

std::variantC++17 中,一個新加入標準函式庫的 template 容器;他的概念基本上是和 union參考)一樣,是一個可以用來儲存多種型別資料的容器。

比如說:

std::variant<int, double> v;

就代表 v 這個變數,可以用來儲存 intdouble 的資料,variant 內部自己會去記錄相關的資訊。

而和 union 不同的地方,variant 也是 type-safe 的,再加上有許多函式可以搭配使用,所以在使用上應該算是相對安全;另外也由於他是標準函式庫的 template class,在使用時不需要另外去宣告一個新的型別。

閱讀更多»