c++ constraints与concepts使用笔记

c++ constraints与concepts使用笔记

      • 1. 模板参数缺乏约束的问题
      • 2. Concepts 基本概念
      • 3. Concept 的定义与使用
      • 4. requires 表达式详解
      • 5. requires 从句 vs requires 表达式
      • 完整示例:约束矩阵运算

1. 模板参数缺乏约束的问题

问题分析

  • 传统模板参数没有语法层面的约束,需要程序员自行通过代码逻辑理解参数要求
  • 编译器错误信息不友好,尤其在传递非法参数时(如 vector<int&>
  • 类型检查发生在模板实例化时,而非声明时

示例

template<typename T>
class Container {T data[10];
public:void copy_from(const Container& other) {std::copy(std::begin(other.data), std::end(other.data), data);}
};struct NonCopyable {NonCopyable(const NonCopyable&) = delete;
};Container<NonCopyable> c;  // 编译错误出现在实例化时的copy操作,而非类定义处

2. Concepts 基本概念

核心特性

  • C++20 引入的编译期谓词机制
  • 通过 requires 子句显式约束模板参数
  • 提升代码可读性和编译器错误信息质量

示例

template<typename T>
concept Arithmetic = std::is_arithmetic_v<T>;template<Arithmetic T>  // 约束T必须是算术类型
T add(T a, T b) { return a + b; }add(3, 5);      // OK
add("a", "b");  // 明确的编译错误:不满足Arithmetic约束

3. Concept 的定义与使用

(1) 单参数 Concept

template<typename T>
concept HasSize = requires(T v) {{ v.size() } -> std::convertible_to<size_t>;
};template<HasSize T>
void print_size(T obj) {std::cout << obj.size() << "\n";
}std::vector v{1,2,3};
print_size(v);  // OK
print_size(42); // 错误:int没有size()方法

(2) 多参数 Concept

template<typename T, typename U>
concept SameAs = std::is_same_v<T, U>;template<typename T>
concept AddableToInt = requires(T a) {{ a + 1 } -> SameAs<int>;  // 使用两参数Concept
};AddableToInt auto result = 'A' + 1;  // OK,char + int 返回int

4. requires 表达式详解

(1) 简单表达式 表明可以接收的操作

template<typename T>
concept Incrementable = requires(T v) {++v;        // 检查前置++v++;        // 检查后置++
};static_assert(Incrementable<int>);     // 通过
static_assert(Incrementable<std::string>); // 失败

(2) 类型表达式 表明是一个有效的类型

template<typename T>
concept HasValueType = requires {typename T::value_type;  // 检查嵌套类型是否存在
};static_assert(HasValueType<std::vector<int>>);  // 通过
static_assert(HasValueType<int>);               // 失败

(3) 复合表达式 表明操作的有效性,以及操作返回类型的特性

template<typename T>
concept StringConvertible = requires(T obj) {{ std::to_string(obj) } -> std::same_as<std::string>;
};static_assert(StringConvertible<int>);    // 通过
static_assert(StringConvertible<void*>);  // 失败

(4) 嵌套表达式 包含其它的限定表达式

template<typename T>
concept CompleteType = requires {sizeof(T);        // 检查类型完整性requires !std::is_void_v<T>;  // 组合多个条件
};static_assert(CompleteType<int>);      // 通过
static_assert(CompleteType<void>);    // 失败

5. requires 从句 vs requires 表达式

关键区别

// requires 从句(用于模板参数约束)
template<typename T>
requires std::is_integral_v<T>  // ← 这是requires从句
void process(T value) { /*...*/ }// requires 表达式(用于定义Concept的约束条件)
template<typename T>
concept Streamable = requires(T v, std::ostream& os) {{ os << v } -> std::same_as<std::ostream&>;
};

完整示例:约束矩阵运算

template<typename T>
concept Numeric = std::is_arithmetic_v<T> && !std::is_same_v<T, bool>;template<typename M>
concept Matrix = requires(const M& mat, size_t i, size_t j) {{ mat.rows() } -> std::convertible_to<size_t>;{ mat.cols() } -> std::convertible_to<size_t>;{ mat(i,j) } -> Numeric;typename M::value_type;requires Numeric<typename M::value_type>;
};template<Matrix A, Matrix B>
auto multiply(const A& a, const B& b) {using T = std::common_type_t<typename A::value_type, typename B::value_type>;std::vector<std::vector<T>> result(a.rows(), std::vector<T>(b.cols()));// ... 矩阵乘法实现return result;
}

以下是对上述代码详细分步解释:

  1. Numeric概念定义
template<typename T>
concept Numeric = std::is_arithmetic_v<T> && !std::is_same_v<T, bool>;
  • 作用:定义数值类型约束,排除布尔类型。
  • 机制
    • std::is_arithmetic_v<T> 检查T是否为算术类型(整型/浮点型,包括bool)。
    • !std::is_same_v<T, bool> 排除bool类型。
  • 合法类型示例int, double, float
  • 排除类型示例bool, std::string
  1. Matrix概念定义
template<typename M>
concept Matrix = requires(const M& mat, size_t i, size_t j) {{ mat.rows() } -> std::convertible_to<size_t>;{ mat.cols() } -> std::convertible_to<size_t>;{ mat(i,j) } -> Numeric;typename M::value_type;requires Numeric<typename M::value_type>;
};
  • 作用:定义矩阵类型的编译期接口约束。
  • 要求
    • 维度接口:必须提供返回size_trows()cols()方法。
    • 元素访问:支持operator(i,j)且返回值满足Numeric
    • 元素类型:必须通过value_type公开元素类型,且该类型满足Numeric
  • 示例合规类型:包含上述方法和嵌套类型的自定义矩阵类。
  1. 矩阵乘法函数模板
template<Matrix A, Matrix B>
auto multiply(const A& a, const B& b) {using T = std::common_type_t<typename A::value_type, typename B::value_type>;std::vector<std::vector<T>> result(a.rows(), std::vector<T>(b.cols()));// 矩阵乘法实现(待填充)return result;
}
  • 模板约束AB必须满足Matrix概念。
  • 实现步骤
    • 公共类型计算std::common_type_t推导两种元素类型的公共可兼容类型(如int+double→double)。
    • 结果容器初始化:创建a.rows()×b.cols()的二维向量,元素默认初始化为T()
    • 乘法逻辑(需补充):典型的三重循环遍历行、列,进行点积运算。

优势

  1. 显式约束矩阵类型必须具有 rows(), cols() 方法
  2. 元素访问操作 operator() 必须返回数值类型
  3. 矩阵元素类型必须满足 Numeric 约束
  4. 编译错误会明确指出具体违反的约束条件

通过合理使用 Concepts 和 requires 表达式,可以显著提升模板代码的可维护性和错误信息的可读性,同时增强接口的自我描述能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/73128.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/73128.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt | 屏幕截图实现

01 全局截屏控件 1. 鼠标右键弹出菜单。 2. 支持全局截屏。 3. 支持局部截屏。 4. 支持截图区域拖动。 5. 支持图片另存为。 演示 点击按钮即可截图 源码: 通过网盘分享的文件:screenwidget屏幕截图 链接: https://pan.baidu.com/s/1PZfQlUXNIoZKEfEtLNV2jQ?pwd=5jsg 提…

2.angular指令

初级使用可以查看视频 参考手册 注意 像ng-class,ng-value,ng-href等这些&#xff0c;很多都可以直接用class“{{}}” 原生写&#xff0c;为啥还出这些指令&#xff0c;是因为原生的比如刚一进页面就先出现表达式了&#xff0c;浏览器走到这里的时候才去解析&#xff0c;给用户…

CTFshow 【WEB入门】信息搜集 【VIP限免】 web1-web17

CTFshow 【 WEB入门】、【VIP限免】 web1 ----源码泄露 首先第一步&#xff0c;看源代码 web2----前台JS绕过 简单点击查看不了源代码&#xff0c;可以强制查看 比如 Ctrl Shift ICtrl U或者在url前加一个view-source: view-source:http://79999ca1-7403-46da-b25b-7ba9…

java 手搓一个http工具类请求传body

import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets;public class HttpUtil {/*** JSON请求发起*/public static String httpJsonRequest(String requestUrl, String requestJson) {String responseJson &…

Spring boot3-WebClient远程调用非阻塞、响应式HTTP客户端

来吧&#xff0c;会用就行具体理论不讨论 1、首先pom.xml引入webflux依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId> </dependency> 别问为什么因为是响应式....…

写了一个二叉树构造函数和画图函数,方便debug

代码 class TreeNode(object):def __init__(self, val, leftNone, rightNone):self.val valself.left leftself.right rightdef construct_tree(nodes):if not nodes:return Noneroot TreeNode(nodes[0])queue [root]index 1while index < len(nodes):node queue.p…

QT:串口上位机

创建工程 布局UI界面 设置名称 设置数据 设置波特率 波特率默认9600 设置数据位 数据位默认8 设置停止位 设置校验位 调整串口设置、接收设置、发送设置为Group Box 修改配置 QT core gui serialport 代码详解 mianwindow.h 首先在mianwindow.h当中定义一个串口指…

【Pandas】pandas Series asof

Pandas2.2 Series Time Series-related 方法描述Series.asfreq(freq[, method, how, …])用于将时间序列数据转换为指定的频率Series.asof(where[, subset])用于返回时间序列中指定索引位置的最近一个非缺失值 pandas.Series.asof pandas.Series.asof 方法用于返回时间序列…

沉浸式CSS学习路径

好的!我将以魔法学院成长故事为框架,为您设计一套沉浸式CSS学习路径。以下是叙事化学习提纲: 第一卷:像素学徒的觉醒 章节1:被封印的魔法书 发现HTML的"素颜"本质,通过<!DOCTYPE html>解除网页封印用style标签打开CSS魔法书,学会给文字穿上color斗篷和…

使用netlify部署github的vue/react项目或本地的dist,国内也可以正常访问

提供简洁的部署流程和丰富功能&#xff0c;如自定义域名、自动构建和服务器端功能。通过连接到 Git 仓库实现持续部署&#xff0c;每次推送代码都会自动构建和发布&#xff0c;支持无服务器函数&#xff0c;允许在前端项目中实现后端逻辑&#xff0c;提供直观的用户界面来管理和…

复现 MoGe

要复现 MoGe&#xff0c;以下给出一般性的复现训练过程步骤示例&#xff09;的训练过程&#xff0c;你可以参考以下步骤&#xff1a; 环境准备 安装必要的深度学习框架&#xff0c;如 TensorFlow 或 PyTorch&#xff0c;以及相关的库&#xff0c;例如用于数据处理的 NumPy、Pan…

Redis-缓存穿透击穿雪崩

1. 穿透问题 缓存穿透问题就是查询不存在的数据。在缓存穿透中&#xff0c;先查缓存&#xff0c;缓存没有数据&#xff0c;就会请求到数据库上&#xff0c;导致数据库压力剧增。 解决方法&#xff1a; 给不存在的key加上空值&#xff0c;防止每次都会请求到数据库。布隆过滤器…

如何在自己的网站接入API接口获取数据?分步指南与实战示例

将第三方API接入自己的网站是获取实时数据、扩展功能的重要手段&#xff08;如展示商品、同步订单、用户登录等&#xff09;。以下是完整的接入流程与关键实践&#xff0c;以微店API为例&#xff0c;适用于多数开放平台。 一、准备工作&#xff1a;注册与权限申请 注册开发者…

刷leetcode hot100--动态规划3.12

第一题乘积max子数组[1h] emmmm感觉看不懂题解 线性dp【计划学一下acwing&#xff0c;挨个做一下】 线性动态规划 相似题解析 最长上升子序列 最大上升子序列和 最大连续子段和 乘积最大子数组_哔哩哔哩_bilibili 比较奇怪的就是有正负数和0&#xff0c;如何处理&#xff1f…

Pytortch深度学习网络框架库 torch.no_grad方法 核心原理与使用场景

在PyTorch中&#xff0c;with torch.no_grad() 是一个用于临时禁用自动梯度计算的上下文管理器。它通过关闭计算图的构建和梯度跟踪&#xff0c;优化内存使用和计算效率&#xff0c;尤其适用于不需要反向传播的场景。以下是其核心含义、作用及使用场景的详细说明&#xff1a; 一…

postgresql 数据库使用

目录 索引 查看索引 创建 删除索引 修改数据库时区 索引 查看索引 select * from pg_indexes where tablenamet_table_data; 或者 select * from pg_statio_all_indexes where relnamet_table_data; 创建 CREATE INDEX ix_table_data_time ON t_table_data (id, crea…

为什么大模型网站使用 SSE 而不是 WebSocket?

在大模型网站&#xff08;如 ChatGPT、Claude、Gemini 等&#xff09;中&#xff0c;前端通常使用 EventSource&#xff08;Server-Sent Events, SSE&#xff09; 来与后端对接&#xff0c;而不是 WebSocket。这是因为 SSE 更适合类似流式文本生成的场景。下面我们详细对比 SSE…

TDengine 数据对接 EXCEL

简介 通过配置使用 ODBC 连接器&#xff0c;Excel 可以快速访问 TDengine 的数据。用户可以将标签数据、原始时序数据或按时间聚合后的时序数据从 TDengine 导入到 Excel&#xff0c;用以制作报表整个过程不需要任何代码编写过程。 前置条件 准备以下环境&#xff1a; TDen…

【具身相关】legged_gym, isaacgym、rsl_rl关系梳理

【legged_gym】legged_gym, isaacgym代码逻辑梳理 总体关系IsaacGymlegged_gymrsl_rl三者的关系 legged_gym代码库介绍环境模块env 总体关系 IsaacGym Isaac Gym 是 NVIDIA 开发的一个高性能物理仿真平台&#xff0c;专门用于强化学习和机器人控制任务。它基于 NVIDIA 的 Phy…

【每日学点HarmonyOS Next知识】状态变量、动画UI残留、Tab控件显示、ob前缀问题、文字背景拉伸

1、HarmonyOS 怎么用一个变量观察其他很多个变量的变化&#xff1f; 有一个提交按钮的颜色&#xff0c;需要很多个值非空才变为红色&#xff0c;否则变为灰色&#xff0c;可不可以用一个变量统一观察这很多个值&#xff0c;去判断按钮该显示什么颜色&#xff0c;比如Button().…