← SEARCHABLE ARCHIVE
C / C++ · 2026-08-10

C++ 從基礎到精通 — 第 16 講

使用 Concepts 與 requires 表達模板需求

INTERACTIVE READING MODE →

本部落格文章以教學為目的撰寫。 內容可能有誤,請搭配目標編譯器與標準函式庫文件確認。

模板能把同一規則套用到多種型別,但不支援的型別常會在實作深處產生冗長錯誤。 C++20 的 Concepts 與 requires 可把需求寫在模板的公開宣告中。

沒有限制的模板

template <typename T>
int GetHealth(const T& value)
{
    return value.Health();
}

此函式只適用於能呼叫 Health() 的型別,但簽章沒有表達這項條件。編譯器必須具現化函式本體後才會發現錯誤。

用 Concept 命名需求

#include <concepts>

template <typename T>
concept Damageable = requires(T value, int amount)
{
    { value.Health() } -> std::convertible_to<int>;
    { value.ApplyDamage(amount) } -> std::same_as<void>;
};

template <Damageable T>
void Attack(T& target, int damage)
{
    target.ApplyDamage(damage);
}

requires expression 不會執行程式碼,只檢查語法與結果型別是否有效。現在呼叫前就能看出 Attack 的需求,錯誤也會更接近呼叫位置。

組合型別條件

template <typename T>
concept SmallId = std::integral<T> && (sizeof(T) <= 4);

template <SmallId T>
void WriteId(T id);

Concept 可用邏輯運算組合 type trait 與 requires。限制條件也會參與多載排序。

void Print(std::integral auto value);
void Print(std::floating_point auto value);

帶 Concept 的 auto 是函式模板的簡寫。當整數與浮點數語意不同時,分離多載通常比在一個函式內塞入大型 if constexpr 更清楚。

語法有效不代表語意正確

a < b 能編譯,不代表比較一定形成一致順序;能複製也不保證兩份資料在語意上彼此獨立。

標準 Concepts 除了語法也記錄語意需求。自訂 Concept 應使用有意義的名稱,重要規則仍要透過測試驗證。

不要加入超過實作需要的限制。應表達最小且真實的契約,避免在沒有提升正確性的情況下拒絕可用型別。