在前一篇《template 型別的需求描述:C++20 concepts(part 1)》,基本上算是簡單介紹了一下 Heresy 知道的 C++20 concepts 的使用概念。
而怎麼制定自己需求的 concept 呢?這邊來稍微整理一下。
首先,C++20 有提供 <concepts> 這個函式庫(參考),提供一些常見的概念,可以來直接使用。而實際上,裡面有很多是使用 C++11 的 <type_traits>(參考)的功能來做的;如果要自行定義 concept 的話,<concepts> 和 <type_traits> 應該都是有幫助的。
Concept 的語法基本上如下:
template<template_parameter_list> concept concept_name = constraint_expression;
例如下面就是一個恆真的 concpet:
template<typename T> concept AlwaysTrue = true;
下面的 concept 則是代表只能是整數類型的型別:
template <class T> concept Integral = std::is_integral_v<T>;
而實際上,在 <concepts> 裡面已經定義了 std::integral(參考)和這邊這個範例是完全相同的。
在 concpet 的定義的時候,也可以使用邏輯計算,像是如果要定義一個無號整數的概念的話,則可以參考 std::unsigned_integral(參考),他的寫法是:
template<class T> concept unsigned_integral = std::integral<T> && !std::signed_integral<T>;
有需要的話,透過 <concepts>(參考)所提供的現成的 concept,也可以很簡單地用來確認類別的繼承關係、或是是否包含某些功能,算是相當方便的~
另外要注意的是,concept 不能被額外限制(不能加上 requires),也不能被做任何的修改(Explicit instantiations、explicit specializations、partial specializations)。
而在需求的表示上,除了上面這種直接去設定 true / false 的方式,其實也可以使用 requires expression 來做比較複雜的驗證。
這時候,他的寫法就是類似下面的樣子:
template<typename T> concept Addable = requires (T x) { x + x; };
透過加上 requires 這個關鍵字,後面可以使用類似函示定義的方式,來撰寫用來驗證是否可以正確編譯的程式。
像以上面的程式來說,編譯器就會去檢查兩個型別為 T 的物件 x 是否可以相加,如果可以,就算是符合需求了。
而這邊的程式碼當然也可以不只一行,可以把有需要驗證的式子都寫進去;當然,由於這邊是要在編譯階段做檢查,所以這邊的程式碼,都是需要再編譯階段就可以確認的東西了。
另外,這邊有個個人覺得比較有趣的「Compound Requirements」;他基本上還可以用來針對表示式的回傳值做驗證。下面就是一個 C++ Reference 給的例子:
template<typename T> concept C2 = requires(T x) { {*x} -> std::convertible_to<typename T::inner>; {x + 1} -> std::same_as<int>; {x * 1} -> std::convertible_to<T>; };
在這個例子,編譯器會檢查:
- *x 是否合法?T::inner 是否合法?以及 *x 的結果是否可以轉換為 T::inner。
- x + 1 是否合法?它的回傳型別是否為 int?
- x * 1 是否合法?他的回傳型別是否可以轉型為 T?
而除了這些用法外,也還有 Type requirements 和 Nested requirements 可以用,不過這部分就請參考 C++ Refernece 的介紹了。
透過這些語法,基本上應該是一定可以寫除符合自己需求的驗證概念了~
Concepts 的部分,暫時可能就先這要了?本來是還有打算多研究一點,寫一些例子出來,但是現階段能找到可供參考的例子看來還是不夠多。
而且現在的 Visual C++ 支援似乎也不算很完整,像是 concept + auto 的語法目前似乎也不能正確編譯,所以大概也就先暫停,等到之後支援更完善再說了吧~
另外,現在的 Visual Studio 16.4 雖然可以正確編譯使用 concpet 的程式了,但是 InteliSense 似乎還是無法正確解析,所以在程式碼顯示的時候會有警告,這時候只能先無視了。
參考: