C++泛型編程指南03-CTAD

文章目錄

      • C++17 自定義類型推斷指引(CTAD)深度解析
        • 一、基礎概念
          • 1. 核心作用
          • 2. 工作原理
        • 二、標準庫中的 CTAD 應用
          • 1. 容器類型推導
          • 2. 智能指針推導
          • 3. 元組類型推導
        • 三、自定義推導指引語法
          • 1. 基本語法結構
          • 2. 典型應用場景
        • 四、推導指引設計模式
          • 1. 迭代器范圍構造
          • 2. 工廠函數模擬
          • 3. 多參數類型合成
        • 五、編譯器行為規則
          • 1. 隱式生成規則
          • 2. 顯式指引優先級
        • 六、高級應用技巧
          • 1. 類型萃取結合
          • 2. 可變參數推導
          • 3. 繼承體系處理
        • 七、典型問題與解決方案
          • 1. 構造函數重載沖突
          • 2. 部分參數推導
          • 3. 防止錯誤推導
        • 八、CTAD 最佳實踐
        • 九、與其他特性的交互
        • 十、編譯器支持與版本控制
  • CTAD例子
      • 示例 1: 自定義容器推導指引
      • 示例 2: 自定義工廠函數推導指引
      • 示例 3: 結合概念約束的推導指引
      • 示例 4: 使用默認模板參數的 CTAD
      • 示例 5: 結合類型轉換的 CTAD
      • 示例 6: 使用可變參數模板的 CTAD

C++17 自定義類型推斷指引(CTAD)深度解析

CTAD(Class Template Argument Deduction,類模板參數推導)是 C++17 引入的重要特性,允許編譯器根據構造函數參數自動推導類模板參數類型。該特性通過 用戶自定義推導指引(User-defined Deduction Guides)實現模板參數類型的智能推導。


一、基礎概念
1. 核心作用
  • 消除冗余類型聲明:無需顯式指定模板參數類型
  • 提升代碼簡潔性:使類模板使用方式接近普通類
  • 增強標準庫易用性:支持std::vector{1,2,3}式初始化
2. 工作原理
template<typename T>
struct MyWrapper {MyWrapper(T value);  // 構造函數
};// 使用 CTAD
MyWrapper w(42);  // 推導為 MyWrapper<int>

二、標準庫中的 CTAD 應用
1. 容器類型推導
std::vector data{1, 2, 3};       // 推導為 vector<int>
std::list names{"Alice", "Bob"}; // 推導為 list<const char*>
2. 智能指針推導
auto p = std::make_shared(5.0);  // shared_ptr<double>
auto u = std::make_unique("text"); // unique_ptr<const char*>
3. 元組類型推導
std::tuple tpl(42, 3.14, "C++"); // tuple<int, double, const char*>

三、自定義推導指引語法
1. 基本語法結構
template<模板參數列表>
ClassName(構造函數參數類型列表) -> 目標模板實例化類型;
2. 典型應用場景
template<typename T>
struct CustomContainer {CustomContainer(T* ptr, size_t size);  // 指針+大小構造
};// 推導指引:從數組創建容器
template<typename T, size_t N>
CustomContainer(T(&)[N]) -> CustomContainer<T>;

四、推導指引設計模式
1. 迭代器范圍構造
template<typename T>
class DataSet {
public:template<typename Iter>DataSet(Iter begin, Iter end);
};// 推導指引
template<typename Iter>
DataSet(Iter, Iter) -> DataSet<typename std::iterator_traits<Iter>::value_type>;
2. 工廠函數模擬
template<typename T>
struct Factory {template<typename... Args>Factory(Args&&... args);
};// 推導指引:根據構造參數推導類型
template<typename... Args>
Factory(Args&&...) -> Factory<std::common_type_t<Args...>>;
3. 多參數類型合成
template<typename T, typename U>
struct Pair {T first;U second;Pair(const T& t, const U& u);
};// 推導指引:自動合成類型
Pair(const auto&, const auto&) -> Pair<std::decay_t<decltype(arg1)>, std::decay_t<decltype(arg2)>>;

五、編譯器行為規則
1. 隱式生成規則

當未顯式提供推導指引時,編譯器會嘗試:

  • 匹配所有構造函數
  • 對每個構造函數生成隱式推導指引
template<typename T>
struct Box {Box(T);           // 生成 Box(T) -> Box<T>Box(T, T);        // 生成 Box(T, T) -> Box<T>
};
2. 顯式指引優先級
template<typename T>
struct Example {Example(T);Example(int);
};// 顯式指引優先于隱式生成
Example(int) -> Example<std::string>;Example e1(42);  // 使用顯式指引 → Example<std::string>
Example e2(3.14); // 使用隱式指引 → Example<double>

六、高級應用技巧
1. 類型萃取結合
template<typename T>
struct SmartPointer {template<typename U>SmartPointer(U* ptr);
};// 使用類型萃取約束指針類型
template<typename U>
requires std::is_base_of_v<BaseClass, U>
SmartPointer(U*) -> SmartPointer<BaseClass>;
2. 可變參數推導
template<typename... Ts>
struct TupleWrapper {TupleWrapper(Ts... values);
};// 推導可變參數類型
TupleWrapper(Ts...) -> TupleWrapper<Ts...>;
3. 繼承體系處理
template<typename T>
struct Base {};template<typename T>
struct Derived : Base<T> {Derived(T);
};// 處理基類模板參數推導
Derived(T) -> Derived<T>;  // 確保正確推導基類參數

七、典型問題與解決方案
1. 構造函數重載沖突
template<typename T>
struct Conflicting {Conflicting(int);Conflicting(T);
};// 解決方案:顯式指定優先級
Conflicting(int) -> Conflicting<int>;
Conflicting(T) -> Conflicting<T>;
2. 部分參數推導
template<typename T, typename U>
struct MixedType {MixedType(T, U);
};// 顯式指定部分參數類型
template<typename U>
MixedType(const char*, U) -> MixedType<std::string, U>;
3. 防止錯誤推導
template<typename T>
struct Dangerous {Dangerous(std::initializer_list<T>);
};// 限制初始化列表類型
template<typename T>
Dangerous(std::initializer_list<T>) -> Dangerous<T>;  // 防止類型退化

八、CTAD 最佳實踐
  1. 謹慎設計構造函數:避免過于通用的構造函數簽名
  2. 優先使用顯式指引:明確表達設計意圖
  3. 結合概念約束(C++20):增強類型安全性
  4. 單元測試驗證:確保推導結果符合預期
  5. 文檔注釋說明:記錄特殊推導規則

九、與其他特性的交互
特性組合應用場景示例代碼片段
CTAD + 結構化綁定同時推導容器元素類型和結構auto [x,y] = Point{1,2};
CTAD + 概念約束類型安全的泛型構造requires integral<T> Vector(T init)
CTAD + 變參模板靈活的類型組合推導Tuple{1, "text", 3.14}
CTAD + 移動語義優化資源管理類型推導UniquePtr ptr(new Resource);

十、編譯器支持與版本控制
編譯器最低支持版本特性完整度
GCC7.0+完整支持
Clang5.0+完整支持
MSVC2017 15.7+完整支持

通過合理應用 CTAD 技術,開發者可以:

  • 顯著提升模板類使用的直觀性
  • 減少冗余的類型聲明代碼
  • 增強模板庫的易用性和可維護性
  • 實現更優雅的 API 設計

建議在實際工程中結合編譯器的診斷信息和靜態斷言(static_assert)進行嚴格驗證,確保類型推導結果符合預期。

CTAD例子

當然可以。以下是完整的代碼示例,包括了之前提到的改進和新增加的例子。每個例子都展示了類模板參數推導(CTAD)的不同應用方式。

示例 1: 自定義容器推導指引

#include <iostream>
#include <typeinfo>template<typename T>
class Container {
public:Container(T* ptr, size_t size) : data(ptr), size(size) {}void print() const {std::cout << "Container of type: " << typeid(T).name() << std::endl;}private:T* data;size_t size;
};// 用戶自定義推導指引
template<typename T, size_t N>
Container(T(&)[N]) -> Container<T>;int main() {int arr[] = {1, 2, 3};Container container(arr);  // 推導為 Container<int>container.print();  // 輸出 "Container of type: i" (取決于編譯器)
}

示例 2: 自定義工廠函數推導指引

#include <iostream>
#include <typeinfo>
#include <type_traits>template<typename T>
class Widget {
public:Widget(T value) : value(value) {}void print() const {std::cout << "Widget of type: " << typeid(T).name() << std::endl;}private:T value;
};// 用戶自定義推導指引
template<typename... Args>
Widget(Args&&...) -> Widget<std::common_type_t<Args...>>;int main() {Widget w(1, 2.0, "three");  // 推導為 Widget<double>w.print();  // 輸出 "Widget of type: d" (取決于編譯器)
}

示例 3: 結合概念約束的推導指引

#include <concepts>
#include <iostream>
#include <typeinfo>template<typename T>
concept Integral = std::is_integral_v<T>;template<Integral T>
class SafeInteger {
public:SafeInteger(T val) : value(val) {}void print() const {std::cout << "SafeInteger of type: " << typeid(T).name() << std::endl;}private:T value;
};// 用戶自定義推導指引
template<Integral T>
SafeInteger(T) -> SafeInteger<T>;int main() {SafeInteger si(42);  // 推導為 SafeInteger<int>si.print();  // 輸出 "SafeInteger of type: i" (取決于編譯器)
}

示例 4: 使用默認模板參數的 CTAD

#include <iostream>
#include <typeinfo>template<typename T, typename U = int>
class Pair {
public:T first;U second;Pair(T f, U s) : first(f), second(s) {}void print() const {std::cout << "Pair of types: " << typeid(T).name() << ", " << typeid(U).name() << std::endl;}
};// 用戶自定義推導指引
template<typename T, typename U>
Pair(T, U) -> Pair<T, U>;int main() {Pair pair(10, 20.5); // 推導為 Pair<int, double>,U 被自動推導為 doublepair.print(); // 輸出 "Pair of types: i, d" (取決于編譯器)
}

示例 5: 結合類型轉換的 CTAD

#include <iostream>
#include <typeinfo>class Base {};
class Derived : public Base {};template<typename T>
class Wrapper {
public:Wrapper(T* ptr) : ptr(ptr) {}void print() const {std::cout << "Wrapper of type: " << typeid(T).name() << std::endl;}private:T* ptr;
};// 用戶自定義推導指引
template<typename T>
Wrapper(T*) -> Wrapper<T>;int main() {Derived derived;Wrapper wrapper(&derived); // 自動推導為 Wrapper<Derived>wrapper.print(); // 輸出 "Wrapper of type: 7Derived" (取決于編譯器)
}

示例 6: 使用可變參數模板的 CTAD

#include <iostream>
#include <typeinfo>template<typename... Args>
class TupleHolder {
public:void print() const {std::cout << "TupleHolder contains types: ";((std::cout << typeid(Args).name() << " "), ...);std::cout << std::endl;}
};// 用戶自定義推導指引
template<typename... Args>
TupleHolder(Args...) -> TupleHolder<Args...>;int main() {TupleHolder holder(1, 'a', 3.14); // 推導為 TupleHolder<int, char, double>holder.print(); // 輸出 "TupleHolder contains types: i a d" (取決于編譯器)
}

這些例子覆蓋了從簡單的容器推導到復雜的類型轉換和可變參數模板的應用。通過使用CTAD技術,您可以簡化模板類的實例化過程,并結合其他現代C++特性來增強代碼的靈活性和安全性。希望這些示例能幫助您更好地理解和應用CTAD技術。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/67786.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/67786.shtml
英文地址,請注明出處:http://en.pswp.cn/web/67786.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

deepseek+vscode自動化測試腳本生成

近幾日Deepseek大火,我這里也嘗試了一下,確實很強。而目前vscode的AI toolkit插件也已經集成了deepseek R1,這里就介紹下在vscode中利用deepseek幫助我們完成自動化測試腳本的實踐分享 安裝AI ToolKit并啟用Deepseek 微軟官方提供了一個針對AI輔助的插件,也就是 AI Toolk…

電介質超表面中指定渦旋的非線性生成

渦旋光束在眾多領域具有重要應用&#xff0c;但傳統光學器件產生渦旋光束的方式限制了其在集成系統中的應用。超表面的出現為渦旋光束的產生帶來了新的可能性&#xff0c;尤其是在非線性領域&#xff0c;盡管近些年來已經有一些研究&#xff0c;但仍存在諸多問題&#xff0c;如…

基于Springboot+mybatis+mysql+html圖書管理系統2

基于Springbootmybatismysqlhtml圖書管理系統2 一、系統介紹二、功能展示1.用戶登陸2.用戶主頁3.圖書查詢4.還書5.個人信息修改6.圖書管理&#xff08;管理員&#xff09;7.學生管理&#xff08;管理員&#xff09;8.廢除記錄&#xff08;管理員&#xff09; 三、數據庫四、其它…

重構字符串(767)

767. 重構字符串 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a; class Solution { public:string reorganizeString(string s){string res;//因為1 < s.length < 500 &#xff0c; uint64_t 類型足夠uint16_t n s.size();if (n 0) {return res;}unordere…

本地部署DeepSeek方法

本地部署完成后的效果如下圖&#xff0c;整體與chatgpt類似&#xff0c;只是模型在本地推理。 我們在本地部署主要使用兩個工具&#xff1a; ollamaopen-webui ollama是在本地管理和運行大模型的工具&#xff0c;可以直接在terminal里和大模型對話。open-webui是提供一個類…

游戲引擎 Unity - Unity 啟動(下載 Unity Editor、生成 Unity Personal Edition 許可證)

Unity Unity 首次發布于 2005 年&#xff0c;屬于 Unity Technologies Unity 使用的開發技術有&#xff1a;C# Unity 的適用平臺&#xff1a;PC、主機、移動設備、VR / AR、Web 等 Unity 的適用領域&#xff1a;開發中等畫質中小型項目 Unity 適合初學者或需要快速上手的開…

【開源免費】基于Vue和SpringBoot的公寓報修管理系統(附論文)

本文項目編號 T 186 &#xff0c;文末自助獲取源碼 \color{red}{T186&#xff0c;文末自助獲取源碼} T186&#xff0c;文末自助獲取源碼 目錄 一、系統介紹二、數據庫設計三、配套教程3.1 啟動教程3.2 講解視頻3.3 二次開發教程 四、功能截圖五、文案資料5.1 選題背景5.2 國內…

Haskell語言的多線程編程

Haskell語言的多線程編程 Haskell是一種基于函數式編程范式的編程語言&#xff0c;以其強大的類型系統和懶惰求值著稱。近年來&#xff0c;隨著多核處理器的發展&#xff0c;多線程編程變得日益重要。雖然Haskell最初并不是為了多線程而設計&#xff0c;但它的設計理念和工具集…

《蒼穹外賣》項目學習記錄-Day11訂單統計

根據起始時間和結束時間&#xff0c;先把begin放入集合中用while循環當begin不等于end的時候&#xff0c;讓begin加一天&#xff0c;這樣就把這個區間內的時間放到List集合。 查詢每天的訂單總數也就是查詢的時間段是大于當天的開始時間&#xff08;0點0分0秒&#xff09;小于…

【python】python油田數據分析與可視化(源碼+數據集)【獨一無二】

&#x1f449;博__主&#x1f448;&#xff1a;米碼收割機 &#x1f449;技__能&#x1f448;&#xff1a;C/Python語言 &#x1f449;專__注&#x1f448;&#xff1a;專注主流機器人、人工智能等相關領域的開發、測試技術。 【python】python油田數據分析與可視化&#xff08…

FBX SDK的使用:基礎知識

Windows環境配置 FBX SDK安裝后&#xff0c;目錄下有三個文件夾&#xff1a; include 頭文件lib 編譯的二進制庫&#xff0c;根據你項目的配置去包含相應的庫samples 官方使用案列 動態鏈接 libfbxsdk.dll, libfbxsdk.lib是動態庫&#xff0c;需要在配置屬性->C/C->預…

【單層神經網絡】基于MXNet庫簡化實現線性回歸

寫在前面 同最開始的兩篇文章 完整程序及注釋 導入使用的庫# 基本 from mxnet import autograd, nd, gluon # 模型、網絡 from mxnet.gluon import nn from mxnet import init # 學習 from mxnet.gluon import loss as gloss # 數據集 from mxnet.gluon…

【爬蟲】JS逆向解決某藥的商品價格加密

??????????歡迎來到我的博客?????????? ??作者:秋無之地 ??簡介:CSDN爬蟲、后端、大數據領域創作者。目前從事python爬蟲、后端和大數據等相關工作,主要擅長領域有:爬蟲、后端、大數據開發、數據分析等。 ??歡迎小伙伴們點贊????、收藏??、…

OpenAI開源戰略反思:中國力量推動AI產業變革

在周五的Reddit問答會上&#xff0c;OpenAI首席執行官Sam Altman罕見承認公司正面臨來自中國科技企業的強勁挑戰。這位向來強硬的硅谷領軍者坦言&#xff0c;以深度求索&#xff08;DeepSeek&#xff09;為代表的中國AI公司正在改寫行業游戲規則。 這場歷時三小時的對話揭示了…

一文講解HashMap線程安全相關問題(上)

HashMap不是線程安全的&#xff0c;主要有以下幾個問題&#xff1a; ①、多線程下擴容會死循環。JDK1.7 中的 HashMap 使用的是頭插法插入元素&#xff0c;在多線程的環境下&#xff0c;擴容的時候就有可能導致出現環形鏈表&#xff0c;造成死循環。 JDK 8 時已經修復了這個問…

android java系統彈窗的基礎模板

1、資源文件 app\src\main\res\layout下增加custom_pop_layout.xml 定義彈窗的控件資源。 <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/…

python學習——常用的內置函數匯總

文章目錄 類型轉換函數數學函數常用的迭代器操作函數常用的其他內置函數 類型轉換函數 數學函數 常用的迭代器操作函數 實操&#xff1a; from cv2.gapi import descr_oflst [55, 42, 37, 2, 66, 23, 18, 99]# (1) 排序操作 asc_lst sorted(lst) # 升序 desc_lst sorted(l…

《解鎖AI黑科技:數據分類聚類與可視化》

在當今數字化時代&#xff0c;數據如潮水般涌來&#xff0c;如何從海量數據中提取有價值的信息&#xff0c;成為了眾多領域面臨的關鍵挑戰。人工智能&#xff08;AI&#xff09;技術的崛起&#xff0c;為解決這一難題提供了強大的工具。其中&#xff0c;能夠實現數據分類與聚類…

MySQL數據庫環境搭建

下載MySQL 官網&#xff1a;https://downloads.mysql.com/archives/installer/ 下載社區版就行了。 安裝流程 看b站大佬的視頻吧&#xff1a;https://www.bilibili.com/video/BV12q4y1477i/?spm_id_from333.337.search-card.all.click&vd_source37dfd298d2133f3e1f3e3c…

AI學習指南HuggingFace篇-Tokenizers 與文本處理

一、引言 在自然語言處理(NLP)中,文本數據的預處理是至關重要的一步。分詞器(Tokenizers)是將文本分割成單詞、短語或其他單元的工具,是文本處理的基礎。Hugging Face的Tokenizers庫提供了高效且靈活的分詞工具,支持多種預訓練模型的分詞需求。本文將深入講解Tokenizer…