Home Item 20 - constexpr if (中文)
Post
Cancel

Item 20 - constexpr if (中文)

constexpr if

constexpr if 是 C++17 中引入的新語法,它允許在編譯時根據條件進行編譯時選擇,從而避免了在模板程式設計中經常需要使用的模板特化和 SFINAE 技術。

SFINAE 是 “Substitution Failure Is Not An Error” 的縮寫,它是 C++ 模板元程式設計中的一種技術。當進行模板實例化時,如果在推斷模板參數或進行模板特化時出現錯誤,SFINAE 技術允許編譯器繼續進行模板實例化而不是報錯。

但是這種功能,會讓你的 code 變得很難讀,一樣,直接看 code

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
29
30
31
32
33
34
// 定義一個函數模板,根據 T 的類型進行特化,用於處理整數型別的資料
template<typename T>
void process_data(const T& data) {
    std::cout << "未知型別的資料" << std::endl;
}

// 模板特化,處理整數型別的資料
template<>
void process_data<int>(const int& data) {
    std::cout << "整數型別的資料:" << data << std::endl;
}

// 模板特化,處理浮點型別的資料
template<>
void process_data<float>(const float& data) {
    std::cout << "浮點型別的資料:" << data << std::endl;
}

// 模板特化,處理字串型別的資料
template<>
void process_data<std::string>(const std::string& data) {
    std::cout << "字串型別的資料:" << data << std::endl;
}

int main() {

    std::string str = "Hello";
    process_data(10);        // 整數型別的資料
    process_data(3.14f);      // 浮點型別的資料
    process_data(str);   // 字串型別的資料
    process_data(true);      // 未知型別的資料

    return 0;
}

使用 constexpr if

code 變得簡單好讀很多

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
// 定義一個函數模板,根據 T 的類型在編譯時進行不同的處理
template<typename T>
void process_data(const T& data) {
    // 使用 constexpr if 在編譯時根據 T 的類型進行選擇
    if constexpr (std::is_integral<T>::value) {
        std::cout << "整數型別的資料:" << data << std::endl;
    }
    else if constexpr (std::is_floating_point<T>::value) {
        std::cout << "浮點型別的資料:" << data << std::endl;
    }
    else if constexpr (std::is_same<T, std::string>::value) {
        std::cout << "字串型別的資料:" << data << std::endl;
    }
    else {
        std::cout << "未知型別的資料" << std::endl;
    }
}

int main() {

    std::string str = "Hello";
    process_data(10);        // 整數型別的資料
    process_data(3.14f);      // 浮點型別的資料
    process_data(str);   // 字串型別的資料
    process_data(true);      // 未知型別的資料

    return 0;
}

結果

Desktop View

在這個例子中,在使用模板特化的版本中 process_data(true) 的輸出是 “未知型別的資料”,而在使用 constexpr if 的版本中 process_data(true) 的輸出是 “整數型別的資料” 的原因是這兩種方法處理條件判斷的方式不同。

在模板特化的版本中,我們為整數型別、浮點型別和字串型別分別定義了特化版本,但沒有為布林型別進行特化。因此,當呼叫 process_data(true) 時,編譯器會尋找與布林型別相關的特化版本,但找不到對應的特化,因此會使用通用的模板版本,輸出 “未知型別的資料”。

而在 constexpr if 的版本中,我們使用 if constexpr 來進行條件判斷,根據條件的成立與否選擇不同的程式碼路徑。在這個情況下,條件是 std::is_integral::value,即判斷類型 T 是否是整數型別。當 T 為布林型別時,std::is_integral::value 會返回 true,因此會選擇 if constexpr 的程式碼路徑,進而輸出 "整數型別的資料"。

把 code 複製下來,實際跑一遍吧!這樣可以更清楚上面再說什麼! Happing coding.

☝ツ☝

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

👈 ツ 👍