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
英文地址,請注明出處:http://en.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().…