定义和使用 concept

下面演示了几种 C++20 支持的定义 concept 的方式,每一条约束都是以下之一,然后用分号结尾:

  1. 类型
  2. 表达式
  3. { 表达式 } noexcept -> 检查返回类型是否满足其他约束(这个 noexcept 可以不要)
  4. 引入其他 requires 表达式
template <typename T>
concept StringConcept = requires(T t) {
    typename T::iterator; // 1. 检查类型存在性
    t.data();             // 2. 检查表达式合法性

    // 3. 将表达式作为 concept 的第一个参数,要求 concept 成立(额外参数从第二个参数起放置)
    { t.c_str() } -> std::same_as<char const *>;

    // 4. 用 requires 语句引入子条件
    requires std::is_pointer_v<decltype(t.data())>;

    // 5. 除了 requires 体之外还能用其他编译期常量表达式做约束
} && (sizeof(T) > 8) && !std::is_aggregate_v<T>;

template<StringConcept Str>
void takeString(Str const &s) { }

int main() {
    takeString(std::string{"hello"});
}

在模板中加上 requires 条件则相对比较简单。只需要在 模板参数后,函数返回值前面,或者 函数体前面 加上 requires 约束。requires 约束能使用一般的条件表达式,也能把 concept 当成 type trait 使用。比如:

template <typename T>
requires HasPlus<T>
int f(T p)
{}

template <typename T>
int g(T p)
requires HasPlus<T>
{}

// 注意 requires 约束的位置比较灵活