C++20 concepts:定義的方式(part 2)

| | 0 Comments| 16:19
Categories:

在前一篇《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 似乎還是無法正確解析,所以在程式碼顯示的時候會有警告,這時候只能先無視了。

參考:

Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *