跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C++20 概念(Concepts):模板参数的语义约束定义

C++20 Concepts 是用于为模板参数定义语义约束的编译期谓词系统。概念的基本定义语法、组合方式及标准库预定义概念。详细讲解了 requires 表达式的四种约束要求:简单要求、类型要求、复合要求和嵌套要求,并结合代码示例说明了其在验证表达式有效性、返回类型及异常规范方面的应用。旨在帮助开发者实现从“语法兼容”到“语义契约”的转变,提升泛型编程的可读性与错误诊断能力。

墨染流年发布于 2026/3/27更新于 2026/10/24128 浏览

C++20 概念(Concepts):模板参数的语义约束定义

什么是概念

概念是一套为模板参数定义语义约束的声明式工具。通过 concept 关键字,它将一组类型必须满足的编译期谓词封装为一个命名的语义契约。其本质是提升模板从'语法兼容'到'语义契约'的编译期接口系统。

它将类型需求从隐式的、被动的'鸭子类型'检测,转变为显式的、主动的、由编译器在实例化前验证的设计约束。核心理念是'约束即文档,文档可执行'。

示例

// 定义一个概念
template<typename T>
concept Integral = std::is_integral_v<T>;

// 使用概念
template<Integral T>
T add(T a, T b) {
    return a + b;
}

add(5, 3);      // 正确
add(5.5, 3.3);  // 编译错误

概念用于指定模板参数必须满足的要求,它是类型和值的约束集合。

概念的定义语法

概念的基本用法是先定义,然后使用。

concept myconcept = 约束;

这里的'约束'可以是 requires 表达式,也可以是标准库提供的概念支持。

基本定义

template<typename T>
concept Drawable = requires(T t) {
    t.draw();
};

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

组合概念

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

template<typename T>
concept Serializable = requires(T t) {
    t.serialize();
    T::deserialize;
};

// 组合多个概念
template<typename T>
concept DataObject = Printable<T> && Serializable<T>;

标准库提供的预定义概念(常用部分)

1. 基础类型概念

  • std::integral<T>:整数类型
  • std::signed_integral<T>:有符号整数类型
  • std::unsigned_integral<T>:无符号整数类型
  • std::floating_point<T>:浮点类型
  • std::arithmetic<T>:整数或浮点类型
  • std::fundamental<T>:基础类型(算术、void、nullptr_t)

2. 类型关系概念

  • std::same_as<T, U>:T 和 U 是相同类型
  • std::derived_from<T, U>:T 公开继承自 U
  • std::convertible_to<T, U>:T 可转换为 U
  • std::common_reference_with<T, U>:有共同引用类型
  • std::common_with<T, U>:有共同类型

3. 比较概念

  • std::equality_comparable<T>:可比较相等(==, !=)
  • std::equality_comparable_with<T, U>:可与 U 比较相等
  • std::totally_ordered<T>:全序(==, !=, <, >, <=, >=)
  • std::totally_ordered_with<T, U>:可与 U 全序比较

4. 对象概念

  • std::movable<T>:可移动构造和赋值
  • std::copyable<T>:可复制构造和赋值
  • std::semiregular<T>:可默认构造且可复制
  • std::regular<T>:正规类型(可默认构造、可复制、可比较相等)
  • std::swappable<T>:可交换
  • std::swappable_with<T, U>:T 和 U 可互相交换

5. 可调用概念

  • std::invocable<F, Args...>:可用 Args... 调用
  • std::regular_invocable<F, Args...>:正规可调用(不修改函数对象)
  • std::predicate<F, Args...>:返回 bool 的可调用
  • std::relation<R, T, U>:二元关系(返回 bool)
  • std::equivalence_relation<R, T, U>:等价关系
  • std::strict_weak_order<R, T, U>:严格弱序

6. 迭代器类别概念

  • std::input_iterator<I>:输入迭代器
  • std::output_iterator<I, T>:输出迭代器(可写入类型 T)
  • std::forward_iterator<I>:前向迭代器
  • std::bidirectional_iterator<I>:双向迭代器
  • std::random_access_iterator<I>:随机访问迭代器
  • std::contiguous_iterator<I>:连续迭代器

7. 迭代器属性概念

  • std::indirectly_readable<I>:可间接读取
  • std::indirectly_writable<I, T>:可间接写入类型 T
  • std::weakly_incrementable<I>:可弱递增
  • std::incrementable<I>:可递增
  • std::indirectly_movable<I1, I2>:可从 I1 移动到 I2
  • std::indirectly_copyable<I1, I2>:可从 I1 复制到 I2

8. 迭代器操作概念

  • std::indirectly_swappable<I1, I2>:可间接交换
  • std::indirectly_comparable<I1, I2, R>:可间接比较
  • std::permutable<I>:可置换
  • std::mergeable<I1, I2, O, R>:可合并
  • std::sortable<I, R>:可排序

9. 范围概念

  • std::ranges::range<R>:范围(有 begin() 和 end())
  • std::ranges::sized_range<R>:有大小信息的范围
  • std::ranges::view<R>:视图(轻量、非拥有范围)
  • std::ranges::borrowed_range<R>:借用范围
  • std::ranges::input_range<R>:输入范围
  • std::ranges::forward_range<R>:前向范围
  • std::ranges::bidirectional_range<R>:双向范围
  • std::ranges::random_access_range<R>:随机访问范围
  • std::ranges::contiguous_range<R>:连续范围

10. 范围适配器概念

  • std::ranges::viewable_range<R>:可转换为视图的范围

requires 表达式语法说明

1. requires 表达式的基本语法结构

// 基本形式
requires (参数列表 (可选)) {
    要求序列
}

// 完整语法图解
requires-expression:
    requires ( parameter-declaration-clause(opt) ) {
        requirement-seq
    }
requirement-seq:
    requirement requirement-seq
    requirement
requirement:
    simple-requirement       // 简单要求
    type-requirement         // 类型要求
    compound-requirement     // 复合要求
    nested-requirement       // 嵌套要求

(1)简单要求 (Simple Requirements)

验证表达式是否有效(是否能编译通过)。

template<typename T>
concept HasMethods = requires(T obj) {
    // 验证成员函数存在
    obj.method1();
    obj.method2();
    // 验证操作符存在
    obj + obj;
    -obj;
    // 验证静态成员存在
    T::static_method();
    // 验证友元函数存在
    std::cout << obj;
    // 验证类型转换存在
    static_cast<double>(obj);
    // 验证模板成员函数
    obj.templatemethod<int>();
    // 验证异常规范(C++20 起)
    noexcept(obj.clear());
};

struct Example {
    void method1() {}
    void method2() {}
    Example operator+(const Example&) const { return *this; }
    Example operator-() const { return *this; }
    static void static_method() {}
    template<typename U> void method() {}
    void clear() noexcept {}
};

static_assert(HasMethods<Example>);

特性: 只检查表达式是否合法,不检查返回类型;表达式中的类型必须完全解析;支持模板成员函数检查;支持 noexcept 检查。

(2)类型要求 (Type Requirements)

验证类型名是否有效。

template<typename T>
concept HasNestedTypes = requires {
    // 验证嵌套类型存在
    typename T::value_type;
    typename T::iterator;
    typename T::const_iterator;
    typename T::difference_type;
    typename T::size_type;
    // 验证模板嵌套类型
    typename T::template rebind<double>::other;
    // 验证类型别名
    typename std::add_const_t<T>;
    typename std::remove_reference_t<T>;
    // 验证复杂类型表达式
    typename std::conditional_t<sizeof(T)==4, int, double>;
    typename decltype(T{})::value_type;
};

// 带有类型检查的容器概念
template<typename T>
concept AllocatorAwareContainer = requires {
    typename T::value_type;
    typename T::allocator_type;
    typename T::size_type;
    typename T::difference_type;
    typename T::reference;
    typename T::const_reference;
    typename T::pointer;
    typename T::const_pointer;
    typename T::iterator;
    typename T::const_iterator;
    typename T::reverse_iterator;
    typename T::const_reverse_iterator;
    requires std::same_as<typename T::allocator_type::value_type, typename T::value_type>;
};

// 智能指针类型检查
template<typename Ptr>
concept SmartPointer = requires {
    typename Ptr::element_type;
    typename std::add_pointer_t<typename Ptr::element_type>;
};

特性: 验证类型名在给定上下文中有效;支持模板嵌套类型检查;支持类型别名检查;支持复杂类型表达式。

(3)复合要求 (Compound Requirements)

验证表达式并检查返回类型和异常规范。

/* 语法:{ 表达式 } noexcept(可选) -> 类型约束 ; */
template<typename T>
concept CompleteContainer = requires(T container) {
    // 基本检查:表达式有效,不检查返回类型
    { container.begin() };
    { container.end() };
    
    // 检查返回特定类型
    { container.size() } -> std::same_as<typename T::size_type>;
    { container.empty() } -> std::convertible_to<bool>;
    { container.max_size() } -> std::same_as<typename T::size_type>;
    
    // 检查返回类型可转换
    { container[0] } -> std::convertible_to<typename T::reference>;
    { container.at(0) } -> std::convertible_to<typename T::reference>;
    { container.front() } -> std::convertible_to<typename T::reference>;
    { container.back() } -> std::convertible_to<typename T::reference>;
    
    // 检查 noexcept
    { container.clear() } noexcept;
    { container.swap(std::declval<T&>()) } noexcept;
    
    // 组合检查:noexcept + 类型约束
    { container.push_back(std::declval<typename T::value_type>()) } noexcept -> std::same_as<void>;
    
    // 检查可能抛出的操作
    { container.reserve(0) } -> std::same_as<void>;
    
    // 使用 decltype 的复杂类型约束
    { container.data() } -> std::same_as<std::add_pointer_t<typename T::value_type>>;
    
    // 检查成员函数指针
    { &T::size } -> std::same_as<typename T::size_type(T::*)() const>;
};

// 数学类型概念
template<typename T>
concept Arithmetic = requires(T a, T b) {
    // 算术运算返回相同类型
    { a + b } -> std::same_as<T>;
    { a - b } -> std::same_as<T>;
    { a * b } -> std::same_as<T>;
    { a / b } -> std::same_as<T>;
    { -a } -> std::same_as<T>;
    { +a } -> std::same_as<T>;
    
    // 比较运算返回 bool
    { a == b } -> std::convertible_to<bool>;
    { a != b } -> std::convertible_to<bool>;
    { a < b } -> std::convertible_to<bool>;
    { a > b } -> std::convertible_to<bool>;
    { a <= b } -> std::convertible_to<bool>;
    { a >= b } -> std::convertible_to<bool>;
    
    // 复合赋值
    { a += b } -> std::same_as<T&>;
    { a -= b } -> std::same_as<T&>;
    { a *= b } -> std::same_as<T&>;
    { a /= b } -> std::same_as<T&>;
    
    // 自增自减
    { ++a } -> std::same_as<T&>;
    { a++ } -> std::same_as<T>;
    { --a } -> std::same_as<T&>;
    { a-- } -> std::same_as<T>;
};

// 函数对象概念
template<typename F, typename... Args>
concept RegularInvocableWith = requires(F f, Args... args) {
    { std::invoke(f, args...) } noexcept(noexcept(std::invoke(f, args...))) -> std::same_as<std::invoke_result_t<F, Args...>>;
};

// 迭代器概念
template<typename I>
concept DereferenceableIterator = requires(I it) {
    { *it } -> std::same_as<std::iter_reference_t<I>>;
    { it.operator->() } -> std::same_as<std::add_pointer_t<std::remove_reference_t<std::iter_reference_t<I>>>>;
    { it[0] } -> std::same_as<std::iter_reference_t<I>>;
};

特性: 检查表达式有效性;可选检查返回类型;可选检查 noexcept;类型约束支持任意概念;支持复杂的类型表达式。

(4)嵌套要求 (Nested Requirements)

在 requires 表达式中添加额外的约束。

template<typename T>
concept ComplexType = requires(T obj) {
    // 简单要求
    obj.operation();
    // 类型要求
    typename T::value_type;
    
    // 嵌套要求:编译时布尔条件
    requires sizeof(T) <= 64;
    requires alignof(T) <= 8;
    requires !std::is_polymorphic_v<T>;
    requires std::is_trivially_copyable_v<T>;
    
    // 嵌套要求:概念检查
    requires std::default_initializable<T>;
    requires std::copyable<T>;
    requires std::movable<T>;
    requires std::totally_ordered<T>;
    
    // 嵌套要求:常量表达式
    requires T::max_size > 0;
    requires (T::version == 1 || T::version == 2);
    
    // 嵌套要求:类型特性
    requires std::is_nothrow_destructible_v<T>;
    requires std::has_virtual_destructor_v<T>;
    
    // 嵌套要求:依赖其他 requires 表达式
    requires requires { obj.nested_operation(); };
    requires requires(T a, T b) { a == b; };
    
    // 嵌套要求:逻辑组合
    requires (std::integral<typename T::value_type> || std::floating_point<typename T::value_type>);
    requires std::same_as<decltype(obj.get()), typename T::value_type*>;
    
    // 嵌套要求:编译时计算
    requires (sizeof(typename T::value_type) * T::element_count <= 1024);
    
    // 嵌套要求:基于模板参数的约束
    requires (std::rank_v<T> == 1);
    
    // 嵌套要求:用户定义类型特性
    requires HasTypeTrait<T>::value;
    
    // 嵌套要求:可变参数模板支持
    requires (std::is_constructible_v<T, int, double, const char*>);
};

// 高级示例:SFINAE 友好概念
template<typename T>
concept Advanced = requires {
    requires requires { typename std::tuple_size<T>::type; typename std::tuple_element_t<0, T>; };
    requires std::is_aggregate_v<T>;
    requires (std::tuple_size_v<T> > 0);
    
    requires requires { T::reflect(); { T::meta_info } -> std::same_as<const char*>; };
    
    requires requires(T obj, std::ostream& os) {
        { obj.serialize(os) } -> std::same_as<std::ostream&>;
    };
    requires requires(T obj, std::istream& is) {
        { T::deserialize(is) } -> std::same_as<T>;
    };
};

// 编译时优化提示概念
template<typename T>
concept Optimizable = requires {
    requires std::is_trivial_v<T>;
    requires std::is_standard_layout_v<T>;
    requires (sizeof(T) % alignof(T) == 0);
    requires std::is_trivially_copyable_v<T>;
    requires std::is_trivially_destructible_v<T>;
    requires !std::is_polymorphic_v<T>;
    requires !std::has_virtual_destructor_v<T>;
    requires std::is_trivially_copy_constructible_v<T>;
    requires std::is_trivially_move_constructible_v<T>;
    requires std::is_trivially_copy_assignable_v<T>;
    requires std::is_trivially_move_assignable_v<T>;
};

// 内存安全概念
template<typename T>
concept MemorySafe = requires {
    requires std::is_nothrow_default_constructible_v<T>;
    requires std::is_nothrow_copy_constructible_v<T>;
    requires std::is_nothrow_move_constructible_v<T>;
    requires std::is_nothrow_copy_assignable_v<T>;
    requires std::is_nothrow_move_assignable_v<T>;
    requires std::is_nothrow_destructible_v<T>;
    requires std::is_nothrow_swappable_v<T>;
    requires (std::is_nothrow_constructible_v<T, int>);
};

特性: 在 requires 表达式内部添加额外约束;支持任意布尔常量表达式;支持概念检查;支持类型特性检查;支持逻辑组合(&&, ||, !);支持依赖其他 requires 表达式。

参数声明语法

// 基本形式
requires(T t) { /* ... */ }

// 多个参数
requires(T t, U u, int n) { /* ... */ }

// 引用参数
requires(T& ref, const T& cref) { /* ... */ }

// 指针参数
requires(T* ptr, const T* cptr) { /* ... */ }

// 右值引用参数
requires(T&& rref) { /* ... */ }

// 数组参数
requires(T arr[10]) { /* ... */ }

// 可变参数模板(C++20 起有限支持)
template<typename... Ts>
concept VariadicConcept = requires(Ts... args) {
    (args + ...);
};

// 默认参数(不允许)
// requires (T t = T{}) { /* ... */ } // 错误!

requires 表达式的求值规则

template<typename T>
concept OrderedEvaluation = requires(T t) {
    requires std::default_initializable<T>;
    requires std::copyable<T>;
    { t.operation2() } -> std::same_as<int>;
    requires requires { t.operation3(); };
};

按顺序求值,短路求值。如果前面的约束失败,后续的约束将不再求值。

目录

  1. C++20 概念(Concepts):模板参数的语义约束定义
  2. 什么是概念
  3. 示例
  4. 概念的定义语法
  5. 基本定义
  6. 组合概念
  7. 标准库提供的预定义概念(常用部分)
  8. 1. 基础类型概念
  9. 2. 类型关系概念
  10. 3. 比较概念
  11. 4. 对象概念
  12. 5. 可调用概念
  13. 6. 迭代器类别概念
  14. 7. 迭代器属性概念
  15. 8. 迭代器操作概念
  16. 9. 范围概念
  17. 10. 范围适配器概念
  18. requires 表达式语法说明
  19. 1. requires 表达式的基本语法结构
  20. (1)简单要求 (Simple Requirements)
  21. (2)类型要求 (Type Requirements)
  22. (3)复合要求 (Compound Requirements)
  23. (4)嵌套要求 (Nested Requirements)
  24. 参数声明语法
  25. requires 表达式的求值规则

更多推荐文章

查看全部
  • C++ 继承机制核心解析
  • 对抗学习原理与代码实战详解
  • Java 模拟算法实战:LeetCode 经典题解
  • 双指针算法:四数之和解题思路与实现
  • w64devkit:Windows C/C++轻量级编译环境搭建指南
  • 算法练习:多重背包、贪心差分、DFS 及路径 DP 题解
  • Stable Diffusion 3.5 LoRA 微调指南
  • Copilot 接入第三方 OpenAI 接口配置方案
  • 基于 Python 的流处理与 RAG 驱动智能 ETL 框架设计
  • MiroFish:基于多智能体的群体智能预测引擎实战
  • OpenClaw 接入自定义模型及 WebUI 智能操作指南
  • Flet:用 Python 构建跨平台桌面与 Web 应用
  • Web SQL Database API:被时代淘汰的浏览器存储技术
  • ORB-SLAM3:开源视觉、视觉惯性及多地图 SLAM 库
  • CentOS 7 源码编译安装 Nginx 完整流程
  • C++ 核心语法与实战指南
  • 在 Apple Silicon Mac 上折腾 Whisper-WebUI 的记录
  • 26 岁后转行程序员晚吗?毕业学员分享真实经验
  • 智能家居面板实战:从原理图到嘉立创EDA成品
  • 可视化大屏项目复盘:前端如何跨越技术与业务鸿沟

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online