当前位置: 首页 > ai >正文

Concepts (C++20)


C++20 Concepts

Concepts 是 C++20 引入的核心特性,用于显式约束模板参数,提升代码可读性和错误提示。以下通过代码示例和原理分步骤解析其用法。


1. 基本概念
  • 目标:显式声明模板参数必须满足的条件。
  • 优势:替代复杂的 SFINAE 和 enable_if,直接约束类型。

2. 定义 Concept

使用 concept 关键字定义约束条件。

示例 1:检查类型是否可打印
#include <iostream>
#include <concepts>template <typename T>
concept Printable = requires(std::ostream& os, T val) {{ os << val } -> std::same_as<std::ostream&>;
};
  • 说明:要求类型 T 必须支持 operator<< 输出到流。

3. 应用 Concept 到函数模板
示例 2:约束函数参数可打印
void print(Printable auto val) {std::cout << val << std::endl;
}int main() {print(42);       // 合法:int 可打印print("Hello");  // 合法:const char* 可打印// print(std::vector<int>{}); // 错误:vector 不满足 Printable
}

4. 标准库预定义 Concepts

使用 <concepts><ranges> 中的标准 Concepts。

示例 3:约束算术类型
template <typename T>
concept Arithmetic = std::integral<T> || std::floating_point<T>;Arithmetic auto square(Arithmetic auto val) {return val * val;
}int main() {square(5);      // 合法:int 是整数类型square(3.14);   // 合法:double 是浮点类型// square("5"); // 错误:const char* 不满足 Arithmetic
}

5. 组合 Concepts

使用逻辑运算符组合多个 Concepts。

示例 4:约束类型可加且结果匹配
template <typename T>
concept Addable = requires(T a, T b) {{ a + b } -> std::same_as<T>;
};template <Addable T>
T add(T a, T b) {return a + b;
}int main() {add(3, 4);      // 合法:int 满足 Addable// add("a", "b"); // 错误:const char* 不满足 Addable
}

6. 在类模板中使用 Concepts
示例 5:约束容器元素可默认构造
#include <concepts>template <std::default_initializable T>
class SafeContainer {T data;
public:SafeContainer() = default;
};int main() {SafeContainer<int> c1;      // 合法:int 可默认构造// SafeContainer<std::unique_ptr<int>> c2; // 错误:unique_ptr 不可默认构造
}

7. 复杂约束与嵌套要求
示例 6:约束类型有 size() 方法且返回整型
template <typename T>
concept HasSize = requires(T t) {{ t.size() } -> std::integral;
};void printSize(HasSize auto obj) {std::cout << obj.size() << std::endl;
}struct Vec {size_t size() const { return 10; }
};int main() {Vec v;printSize(v);           // 合法:Vec 有 size() 返回 size_t// printSize(42);       // 错误:int 没有 size()
}

8. 标准库 Concepts 示例

直接使用标准库中的 Concepts。

示例 7:使用 std::sort 约束可排序范围
#include <vector>
#include <algorithm>
#include <ranges>void sortAndPrint(std::ranges::sortable auto& range) {std::sort(range.begin(), range.end());
}int main() {std::vector<int> vec{5, 3, 1, 4, 2};sortAndPrint(vec);      // 合法:vector 支持随机访问迭代器// std::list<int> lst{5, 3}; // sortAndPrint(lst);  // 错误:list 迭代器不支持随机访问
}

9. 原理与编译器行为
  • 替换检查:编译器在模板实例化时验证 Concept 约束。
  • 错误提示:直接指出违反的约束条件,而非模板实例化失败。
  • 零开销:所有检查在编译期完成,无运行时负担。

总结

操作语法示例用途
定义 Concepttemplate<typename T> concept C = ...;声明模板参数的显式约束
函数模板约束void func(C auto param)限制参数类型满足 Concept
组合 ConceptsC1 && C2 或 `C1
类模板约束template<C T> class X {};约束类模板参数
标准库 Conceptsstd::integral<T>, std::sortable快速实现通用约束

Concepts 显著提升了模板代码的可读性和健壮性,结合现代 C++ 特性(如简写模板),使得泛型编程更加直观高效。


多选题


题目 1:Concepts 的基本约束与函数模板重载

以下代码的输出是什么?

#include <iostream>
#include <concepts>template <typename T>
concept HasValue = requires(T t) { t.value; };struct A { int value; };
struct B {};void process(HasValue auto obj) { std::cout << "HasValue" << std::endl; }
void process(auto obj) { std::cout << "Generic" << std::endl; }int main() {A a;B b;process(a); // 调用哪个版本?process(b); // 调用哪个版本?return 0;
}

A. HasValueGeneric
B. GenericGeneric
C. 编译失败,重载冲突
D. 运行时错误


题目 2:组合 Concepts 的逻辑

以下代码是否能编译通过?

#include <concepts>template <typename T>
concept Integral = std::integral<T>::value;template <typename T>
concept Floating = std::floating_point<T>::value;template <typename T>
concept Number = Integral<T> || Floating<T>;template <Number T>
T add(T a, T b) { return a + b; }int main() {auto x = add(3, 4);       // intauto y = add(3.5, 4.5);   // doubleauto z = add("a", "b");   // const char*return 0;
}

A. 编译成功
B. 编译失败,add("a", "b") 不满足 Number
C. 编译失败,Number 的约束定义错误
D. 运行时错误


题目 3:标准库 Concepts 与迭代器约束

以下代码的输出是什么?

#include <vector>
#include <list>
#include <ranges>template <typename T>
void checkRange(T&& range) {if constexpr (std::ranges::random_access_range<T>) {std::cout << "Random Access";} else if constexpr (std::ranges::bidirectional_range<T>) {std::cout << "Bidirectional";} else {std::cout << "Generic";}
}int main() {std::vector<int> vec;std::list<int> lst;checkRange(vec);  // 输出什么?checkRange(lst);  // 输出什么?return 0;
}

A. Random AccessBidirectional
B. Random AccessGeneric
C. BidirectionalBidirectional
D. 编译失败,约束不合法


题目 4:嵌套要求与复杂约束

以下代码是否能编译通过?

#include <concepts>template <typename T>
concept ComplexCheck = requires(T t) {requires std::integral<decltype(t.value)>;{ t.print() } -> std::same_as<void>;
};struct Valid { int value; void print() {} };
struct Invalid1 { double value; void print() {} };
struct Invalid2 { int value; };ComplexCheck auto process(auto obj) { obj.print(); }int main() {process(Valid{});     // 合法?process(Invalid1{});  // 合法?process(Invalid2{});  // 合法?return 0;
}

A. 仅 Valid 合法
B. ValidInvalid1 合法
C. 所有调用均合法
D. 编译失败,ComplexCheck 定义错误


题目 5:Concepts 与模板特化的优先级

以下代码的输出是什么?

#include <iostream>
#include <concepts>template <typename T>
concept Large = sizeof(T) > 4;void process(Large auto t) { std::cout << "Large"; }
void process(auto t) { std::cout << "Generic"; }int main() {process(10);      // int(sizeof(int) = 4)process(10L);     // long(sizeof(long) = 8)return 0;
}

A. GenericLarge
B. LargeLarge
C. GenericGeneric
D. 编译失败,重载冲突


答案与解析


题目 1:Concepts 的基本约束与函数模板重载

答案:A
解析

  • process(HasValue auto) 的约束更严格,优先于无约束的 process(auto)
  • A 满足 HasValue(有 value 成员),调用第一个版本;B 不满足,调用第二个版本。
  • 选项 C 错误:Concepts 约束的函数和非约束函数可以合法重载,优先选择更特化的版本。

题目 2:组合 Concepts 的逻辑

答案:B
解析

  • Number 约束 T 必须是整数或浮点类型。
  • add("a", "b") 中的 const char* 不满足 Number,导致编译失败。
  • 选项 C 错误Number 定义正确,Integral<T> || Floating<T> 语法合法。

题目 3:标准库 Concepts 与迭代器约束

答案:A
解析

  • std::vector 的迭代器是随机访问迭代器,输出 Random Access
  • std::list 的迭代器是双向迭代器,输出 Bidirectional
  • 选项 D 错误:标准库 Concepts 的定义合法。

题目 4:嵌套要求与复杂约束

答案:A
解析

  • ComplexCheck 要求:
    1. t.value 的类型必须满足 std::integral
    2. t.print() 必须存在且返回 void
  • 只有 Valid 满足所有条件:
    • Invalid1value 类型是 double,不满足 std::integral
    • Invalid2 没有 print() 方法。

题目 5:Concepts 与模板特化的优先级

答案:A
解析

  • process(10)intsizeof 为 4,不满足 Large,调用 Generic
  • process(10L)longsizeof 为 8,满足 Large,调用 Large
  • 选项 D 错误:Concepts 约束的函数和非约束函数可以合法重载,无冲突。

总结

通过这组题目,可以深入理解 Concepts 的以下核心机制:

  1. 重载优先级:约束更严格的函数优先匹配。
  2. 组合逻辑:通过 &&|| 组合多个 Concepts。
  3. 标准库集成:如 std::ranges::random_access_range
  4. 嵌套要求:使用 requires 子句细化约束条件。
  5. 编译时决策:基于 sizeof 等编译期属性选择实现。
http://www.xdnf.cn/news/1745.html

相关文章:

  • 【Linux】网络基础和socket(4)
  • 访问者模式
  • HOJ.单词统计
  • 系统架构师2025年论文《系统架构风格2》
  • 生成运算树
  • AIP代码生成器——标准化接口开发智能工具
  • SpringMVC知识体系
  • 【MySQL数据库入门到精通-06 DCL操作】
  • 《数据结构之美--栈和队列》
  • 三格电子Profinet从站转EtherNet/IP从站网关:工业通信协议转换的桥梁
  • 每日Python 4.24
  • 动态自适应分区算法(DAPS)设计流程详解
  • 深度学习:迁移学习
  • 2025年04月24日Github流行趋势
  • 那些年开发踩过的坑
  • day002
  • C++/Qt中QActionGroup类用法
  • 100.HTB-Meow
  • Redis高级数据类型解析(二)——Set、Sorted Set与Geo实战指南
  • 怎么设定自动化测试目标?
  • AI打开潘多拉魔盒?当深度伪造成为虚假信息的核动力引擎
  • RAG 的完整流程是怎么样的?
  • 【扣子Coze 智能体案例四】五行八卦占卜智能体
  • ESP32_IDF_VScode安装多版本共存
  • MySQL-自定义函数
  • 济南国网数字化培训班学习笔记-第二组-2节-输电线路施工及质量
  • Spring MVC HandlerAdapter 的作用是什么? 为什么 DispatcherServlet 不直接调用 Controller 方法?
  • Redis Cluster 使用 CRC16 算法实现 Slot 槽位分片的核心细节
  • VocalPitchMonitor汉化版:专业音调检测,助力歌唱练习
  • 从零开始在Win上添加一块QEMU开发板(四)实现简单USART