Effective C++ 條款42:了解 typename 的雙重含義

Effective C++ 條款42:了解typename的雙重含義

核心思想在模板聲明中,typenameclass可互換使用,但在模板內部,typename必須用于顯式指明嵌套從屬類型名稱(nested dependent type name),以避免編譯器解析歧義。對于非從屬名稱或基類成員列表中的嵌套從屬類型名稱,不得使用typename

?? 1. typename的兩種用途

用法對照

場景關鍵字示例說明
模板參數聲明class/typenametemplate<class T>template<typename T>兩者完全等價
嵌套從屬類型名稱前綴typenametypename T::const_iterator it;必須使用typename標識類型
基類列表中的名稱class Derived: public Base<T>::Nested { ... }基類列表中不能使用typename
初始化列表中的名稱Derived(int x) : Base<T>::Nested(x) { ... }成員初始化列表不能使用typename

代碼示例

template<typename T>
class MyVector {
public:// 嵌套從屬類型名稱:必須使用typenametypedef typename T::iterator iterator; // 正確:typename聲明iterator是類型// 錯誤:缺少typename導致編譯錯誤// typedef T::const_iterator const_iterator;void print(const T& container) {// 嵌套從屬類型名稱:必須使用typenametypename T::const_iterator cit = container.begin(); // 正確// 非從屬名稱:不需要typenameint value = 42; // 非從屬名稱,直接使用}
};

🚨 2. typename的規則與例外

決策矩陣

場景是否使用typename原因示例
模板參數聲明可選(class/typename)兩者等價template<typename T>
嵌套從屬類型名稱前必須避免解析歧義typename T::iterator it;
基類列表中的嵌套類型禁止語法規定class Derived : Base<T>::Nested { ... }
成員初始化列表中的嵌套類型禁止語法規定Derived() : Base<T>::Nested() { ... }
非從屬名稱禁止不需要int value;
顯式特化/實例化禁止不在模板定義中在特化中直接使用具體類型

錯誤使用案例

template<typename T>
class Widget {
public:// 錯誤:在基類列表中使用typename// class WidgetDerived : typename Base<T>::Nested { ... };// 錯誤:在初始化列表中使用typename// Widget() : typename Base<T>::Nested() { ... }// 錯誤:非從屬名稱使用typename// typename int value;
};

嵌套從屬名稱解析規則

template<typename T>
void process(const T& container) {// 假設T是一個容器類型,有const_iterator成員類型T::const_iterator it1 = container.begin(); // 可能被解析為靜態成員變量(錯誤)typename T::const_iterator it2 = container.begin(); // 正確:明確為類型
}

?? 3. 最佳實踐與適用場景

場景1:標準容器迭代器

template<typename Container>
void printContainer(const Container& c) {// 必須使用typename標識嵌套從屬類型typename Container::const_iterator it;for (it = c.begin(); it != c.end(); ++it) {std::cout << *it << ' ';}
}

場景2:模板元編程中的類型萃取

template<typename T>
struct TypeTraits {// 使用typename提取迭代器關聯的類型typedef typename T::value_type value_type;typedef typename T::iterator_category iterator_category;
};// 使用
template<typename Iter>
void advance(Iter& it, int n) {// 使用typename獲取類型特征typename TypeTraits<Iter>::iterator_category category;// ... 根據分類實現advance
}

現代C++增強

// C++11 using別名模板
template<typename T>
using RemoveReference = typename std::remove_reference<T>::type;// C++14起,標準庫類型萃取有_v和_t版本,避免typename
template<typename T>
void func() {std::remove_reference_t<T> x; // 等價于typename std::remove_reference<T>::type
}

💡 關鍵設計原則

  1. 模板參數聲明自由選擇

    // class和typename在模板參數聲明中完全等價
    template<class T> class A;
    template<typename T> class B;
    
  2. 嵌套從屬類型必須加typename

    template<typename T>
    class Demo {
    public:// T::SubType 可能是類型或靜態成員typename T::SubType member; // 必須加typename
    };
    
  3. 基類和初始化列表禁止加typename

    template<typename T>
    class Derived : public Base<T>::Nested { // 基類列表中不能加typename
    public:Derived(int x) : Base<T>::Nested(x) { ... } // 初始化列表中不能加
    };
    

依賴類型解析實戰

template<typename Iter>
auto getValue(Iter it) -> typename std::iterator_traits<Iter>::value_type {return *it;
}// C++14起可用decltype(auto)簡化
template<typename Iter>
decltype(auto) getValueSimplified(Iter it) {return *it;
}

模板元編程中的typename

// 檢查T是否有名為type的嵌套類型
template<typename T, typename = void>
struct HasType : std::false_type {};template<typename T>
struct HasType<T, typename std::void_t<typename T::type>> : std::true_type {};// 使用
static_assert(HasType<std::underlying_type<int>>::value, "has type");

te

struct HasType<T, typename std::void_t> : std::true_type {};

// 使用
static_assert(HasType<std::underlying_type>::value, “has type”);

總結<:typename在C++模板編程中有雙重角色。在聲明模板參數時,它與class等價;在模板內部,它必須用于標識嵌套從屬類型名稱,以避免編譯器將類型解釋為靜態成員。在基類列表和成員初始化列表中,即使出現嵌套從屬類型名稱,也不得使用typename。隨著C++14引入_t_v類型萃取輔助,部分場景可避免顯式使用typename,但在通用模板編程中仍需謹慎遵循規則。

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

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

相關文章

ENCOPIM, S.L. 參展 AUTO TECH China 2025 廣州國際汽車技術展覽會

ENCOPIM, S.L. 參展 AUTO TECH China 2025 廣州國際汽車技術展覽會2025年11月21-24日中國進出口商品交易會展館D區(廣州)AUTO TECH China 2025同期&#xff1a;第二十三屆廣州車展即將盛大開幕展商推薦ENCOPIM, S.L.展位號&#xff1a;3916企業簡介&#xff1a;ENCOPIM, S.L.于…

30 HTB Soccer 機器 - 容易

主要知識點 第一階段&#xff1a;偵查 nmap nmap快速掃描&#xff1a; oxdfhacky$ nmap -p- --min-rate 10000 10.10.11.194 Starting Nmap 7.80 ( https://nmap.org ) at 2023-06-04 13:32 EDT Nmap scan report for 10.10.11.194 Host is up (0.093s latency). Not shown:…

阿里云機器翻譯接口SDK-RAM權限配置

用戶授權翻譯權限在數字化時代&#xff0c;短信作為企業與用戶溝通的重要橋梁&#xff0c;其高效、可靠的送達直接影響業務轉化與用戶體驗。SDK&#xff08;軟件開發工具包&#xff09;的出現極大簡化了短信功能的集成過程&#xff0c;讓開發者能夠快速在應用中嵌入短信驗證、通…

ESXI 6.7服務器時間錯亂問題

1. 設置ESXI服務器&#xff1a;在此主機上手動配置日期和時間管理-服務-ntpd-鼠標右鍵-策略-手動啟動和停止&#xff0c;狀態已停止管理-系統-時間和日期-編輯設置-檢查是否選擇了【在此主機上手動配置日期和時間】ntp服務狀態已停止ntp服務器已停止2. 停止所有虛擬機自動更新時…

CV 醫學影像分類、分割、目標檢測,之【皮膚病分類】項目拆解

CV 醫學影像分類、分割、目標檢測&#xff0c;之【皮膚病分類】項目拆解第1-12行&#xff1a;導入庫第14-17行&#xff1a;讀取標簽文件第19-21行&#xff1a;獲取疾病名稱第23-26行&#xff1a;獲取圖片名列表第28-35行&#xff1a;篩選有標簽的圖片第38-43行&#xff1a;提取…

【JavaEE】多線程 -- 線程狀態

目錄六大狀態舉例說明六大狀態 New 新建狀態&#xff1a;線程還沒出創建&#xff0c;只有Thread 實例化的對象&#xff0c;調用start 方法之前的狀態。Runnable 運行狀態&#xff1a;被系統調度后&#xff0c;CPU 正在執行的&#xff0c;Ready 就緒態&#xff0c;系統調度&…

網絡流初步

網絡流初步 文章目錄網絡流初步概念介紹最大流費用流概念介紹 網絡流不同之處在于它的本質圖論&#xff0c;但是把圖論的某些概念換了一個說法而已&#xff0c;初步只要了解網絡流的各個概念就可以明白的很快。 下述概念是本人自己定義的&#xff0c;對于網絡流的題目做的還不…

[系統架構設計師]系統架構基礎知識(一)

[系統架構設計師]系統架構基礎知識&#xff08;一&#xff09; 一.計算機系統基礎知識 1.計算機系統概述 硬件軟件及網絡組成的系統 2.計算機硬件基礎知識 馮 諾依曼結構&#xff1a;運算器&#xff0c;控制器&#xff0c;存儲器&#xff0c;輸入設備&#xff0c;輸出設備 專用…

深入解析Java代理模式:靈活控制對象訪問的核心技術

在日常開發中&#xff0c;我們常遇到這樣的場景&#xff1a;需要控制對象訪問權限、優化高成本操作&#xff0c;或給方法添加額外功能&#xff08;如日志、事務&#xff09;。代理模式&#xff08;Proxy Pattern&#xff09; 正是解決這類問題的金鑰匙。作為結構型設計模式的代…

【學習筆記】Java并發編程的藝術——第9章 Java中的線程池

第9章 Java中的線程池 線程池優勢&#xff1a; ①減少資源消耗 ②提高響應速度 ③統一管理 9.1 線程池的實現原理 當任務來后 ①判斷核心線程池是否已滿&#xff0c;若未滿&#xff0c;創建一個核心線程來執行任務 ②若無空閑核心線程且核心線程已滿&#xff0c;則將任務放入任…

Mybatis學習筆記(九)

常見問題與解決方案 簡要描述&#xff1a;總結MyBatis-Plus開發過程中常見的問題、錯誤及其解決方案&#xff0c;幫助開發者快速定位和解決問題。 核心概念&#xff1a; 常見錯誤&#xff1a;開發中經常遇到的錯誤類型性能問題&#xff1a;性能相關問題的排查和解決配置問題&am…

數據類型 list

一、介紹類似于數組&#xff0c;順序表&#xff0c;deque結構圖特點&#xff1a;元素有序&#xff0c;元素允許重復由于頭尾高效插入刪除&#xff0c;可以模擬棧&#xff0c;隊列二、常見 list 命令1、lpush key elem [elem ...]頭插元素&#xff0c;返回值列表長度2、lrange k…

pyqt5無法顯示opencv繪制文本和掩碼信息

背景&#xff1a;pyqt5無法顯示opencv繪制的標簽和mask&#xff1b;我們在使用YOLO做實例分割做推理時&#xff0c;會使用opencv做后處理結果繪制&#xff08;含標簽繪制和掩碼繪制&#xff09;&#xff1b;結果opencv繪制的解碼卻無法在pyqt的解碼上面顯示。pyqt轉換代碼如下&…

如何生成嚴格遞增的分布式id?

本文字數&#xff1a;2604字預計閱讀時間&#xff1a;15分鐘01引言在現有分布式系統中&#xff0c;面對增長迅速的業務數據&#xff0c;id生成一直是非常重要的一環。而分布式系統的id生成方案需要滿足幾個重要特性&#xff1a;容錯高可用、高性能高并發、全局唯一。02技術背景…

【LeetCode】二叉樹相關算法題

目錄1、二叉樹介紹【1】核心概念【2】關鍵特性2、算法題【1】二叉樹的前序遍歷【2】二叉樹的后序遍歷1、二叉樹介紹 【1】核心概念 結構含義節點結構二叉樹由節點組成&#xff0c; 每個節點包含一個數據元素和最多兩個子節點&#xff1a;左子節點和右子節點根節點樹的頂部節點…

Vulnhub Deathnote靶機復現攻略

一、靶機安裝 下載地址&#xff1a;https://download.vulnhub.com/deathnote/Deathnote.ova 下載好后使用VB打開&#xff0c;配置如下 二、主機發現 使用相同連接方式的kali進行后續操作(172.16.2.7)根據mac地址進行確認。 nmap -sn 172.16.2.1/24 三、端口掃描 端口開放了…

DevEco Studio 6.0.0 元服務頁面跳轉失敗

背景&#xff0c;我使用最新的編輯器DevEco Studio 6.0.0&#xff0c;編寫一個元服務&#xff0c;發現使用跳轉頁面的時候失敗了&#xff01;然后查看官方文檔&#xff0c;兩種方式都測試了&#xff0c;發現都不行。 方法1&#xff1a;Navigation路由跳轉無效&#xff0c;見官方…

docker重啟或系統重啟后harbor自動啟動

docker重啟或系統重啟后harbor自動啟動docker重啟或系統重啟后harbor自動啟動方法 1&#xff1a;在 docker-compose.yml 中配置重啟策略&#xff08;推薦&#xff09;方法 2&#xff1a;創建 Systemd 服務&#xff08;更可靠&#xff09;方法 3&#xff1a;使用 Docker 的 Rest…

OpenZeppelin Contracts 架構分層分析

OpenZeppelin Contracts 是一個面向以太坊&#xff08;及兼容 EVM 的區塊鏈&#xff09;生態系統的??模塊化、安全性優先、標準兼容的智能合約庫??。其內部代碼按照功能職責與抽象層級&#xff0c;可系統性地劃分為多個邏輯層次。理解這些層次及其依賴關系&#xff0c;對于…

Java-JVM的內存模型

一.JVM內存模型JVM內存模型可以從進程生命周期和線程生命周期1.線程生命周期每個線程都會有自己各自一份數據&#xff0c;不會存在線程安全問題1.程序計數器指示當前線程執行的字節碼指令的行號&#xff0c;以便線程執行時可以回到正確的位置2.虛擬機棧線程私有的&#xff0c;與…