Home Item 23 - 概念(Concepts)(中文)
Post
Cancel

Item 23 - 概念(Concepts)(中文)

概念(Concepts)

在 C++20 中,概念(Concepts)是一種新的語法工具,用於約束模板參數,以提高模板代碼的可讀性和錯誤提示。 概念可以幫助開發者在編譯時期捕捉錯誤,並提供更具體的錯誤信息。 概念是用來定義模板參數所需滿足的條件。 這些條件通常是型別特性、方法簽名或其他編譯時期可檢查的性質。 概念使得模板代碼更加直觀和易於理解,並且可以大大減少模版使用錯誤時的錯誤訊息。

c++ template 是個強大功能,但是缺點就是如果有使用錯誤,錯誤訊息實在又臭又長, 而且根本不知道錯在哪裡..

簡單例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 template<typename T>
 T Add(T a, T b)
 {
     return a + b;
 }

 class Class1
 {
 public:
     Class1(int value)
     {
         this->value = value;
     }

     int value;
 };


 int main()
 {
     std::cout << Add(3, 5) << std::endl;
     std::cout << Add(3.3, 5.5) << std::endl;
     Class1 c1(3);
     Class1 c2(5);
     std::cout << Add(c1, c2) << std::endl;

     return 0;
 }

明眼的人就很快看出來 Add(c1, c2) 會錯,因為 Class1 沒有實作 operator+, 這邊要說的是光是這樣簡單的錯誤,錯誤訊息多達 200 多行…

類型形參(Type Parameters)

概念可以用於類型形參,限制泛型類型:

我們先來定義一個整數概念,使用 std::is_integral_v, 簡單來說除了 double 和 float 以外,其餘原生的數字類回傳都是 true.

1
2
template<typename T>
concept Integral = std::is_integral_v<T>;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <concepts>
#include <limits>

template<typename T>
concept Integral = std::is_integral_v<T>;

// 用於類型形參(Type Parameters)
template<Integral T>
class IntegralNumericLimits {
public:
    static T min() { return std::numeric_limits<T>::min(); }
    static T max() { return std::numeric_limits<T>::max(); }
};

int main() {
    std::cout <<" IntegralNumericLimits<bool>::max() : " << IntegralNumericLimits<bool>::max() << std::endl;
    std::cout << " IntegralNumericLimits<int>::max() " << IntegralNumericLimits<int>::max() << std::endl;
    std::cout << " IntegralNumericLimits<unsigned int>::max() : " << IntegralNumericLimits<unsigned int>::max() << std::endl;
    std::cout << " std::numeric_limits<double>::max() : " << std::numeric_limits<double>::max() << std::endl;

    return 0;
}

執行結果

Desktop View

帶入 double

1
std::cout << " IntegralNumericLimits::max() : " << IntegralNumericLimits<double>::max() << std::endl;

錯誤資訊明確!!!

Desktop View

requires 表達式

requires 表達式可以用來檢查特定條件是否滿足,例如類型是否有某些成員函數或屬性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <concepts>

template<typename T>
concept Printable = requires(T t) {
    { std::cout << t };
};

class Printer {
public:
    void print(Printable auto value) {
        std::cout << "Printing: " << value << std::endl;
    }
};

int main() {
    Printer printer;
    printer.print(58);    // OK
    printer.print("Hello, World!"); // OK
    //printer.print(std::vector<int>{1, 2, 3}); // 編譯錯誤,因為 vector 不滿足 Printable
    return 0;
}

Desktop View

帶入 vector

1
printer.print(std::vector<int>{1, 2, 3});

編譯錯誤,因為 vector 不滿足 Printable

Desktop View

使用時機

概念適用於以下情境:

  1. 提高模板代碼的可讀性: 使用概念可以使模板參數的需求更加明確,代碼易於理解。
  2. 改善錯誤提示: 編譯器可以在編譯時期檢查參數是否滿足概念,並提供更具體的錯誤信息,而不是在使用模板時出現模糊的編譯錯誤。
  3. 強化代碼約束: 使用概念可以避免在模板中使用不適合的型別,增加代碼的安全性和穩定性。

☝ツ☝

This post is licensed under CC BY 4.0 by the author.

👈 ツ 👍

Item 23 - Concepts(English)

Item 27 - Modules(English)