11,模板泛化、模板特化、所占字節數、繼承實現模板展開、using循環命名展開可變參數

模板泛化、模板特化、所占字節數、繼承實現模板展開、using循環命名展開可變參數

  • 模板泛化
  • 模板特化
    • 模板全特化
    • 通過模板偏特化獲取類型所占字節數
      • 通過模板偏特化和宏獲取類型所占字節數
        • ...ParamTypes和ParamTypes...的區別
    • 通過繼承實現模板展開
        • using
    • 通過using循環命名的方式來展開可變參數

模板泛化

當前不知道是什么類型,調用時才知道是什么類型

advanced.h

#pragma once
#include <iostream>
using namespace std;//泛化:所有的模板參數類型都未定義,當使用時才知道
template<class T1,class T2/* typename ...ParamTypes*/>//類型和可變參數的類型都不知道
class FHello_Class
{
private:T1 a;T2 b;
};

學習.cpp

#include <iostream>
#include"advanced.h"int main()
{FHello_Class<int, float>A;return 0;
}

模板特化

特化是一種模板技術

模板全特化

必須寫一個模板泛化做匹配,否則用不了

模板特化是一種將模板參數替換為具體類型或值的過程

#pragma once
#include <iostream>
using namespace std;//泛化:所有的模板參數類型都未定義,當使用時才知道
template<class T>
class FHello_Class
{
private:T1 a;T2 b;
};//特化(全特化):模板特化是一種將模板參數替換為具體類型或值的過程
template<>
class FHello_Class<int>//給定的類型一定是具體的
{};
/*template<>
class FHello_Class1<int, float>//因為沒有對應的模板泛化,所以會報錯
{};*///函數全特化
template<class T>
void FunTest()
{};
template<>
void FunTest<int>()
{}

模板特化分為模板全特化和模板偏特化

全特化(Full Specialization)和偏特化(Partial Specialization)是C++中模板特化的兩種形式。

全特化是指對完整的模板進行特化,也就是將模板中的所有參數都替換為具體的類型或值。全特化通過使用特定的類型或值提供完整的特化定義。例如:

template<typename T, int N>
class Array
{
public:T elements[N];
};template<>
class Array<int, 5>
{
public:int elements[5];
};

在上面的例子中,我們定義了一個通用的模板類 Array,包含一個類型參數 T 和一個整數參數 N。然后我們使用全特化對類型參數為 int,整數參數為 5 的情況進行了特化。這意味著當我們使用 Array<int, 5> 這個類型時,將使用全特化的定義,即 Array<int, 5> 類型將有一個 int 類型的數組成員。

偏特化是指對模板中的部分參數進行特化。偏特化允許我們針對特定的參數組合提供不同的定義。例如:

template<typename T, typename U>
class Pair
{
public:T first;U second;
};template<typename T>
class Pair<T, T>
{
public:T element;
};

在上面的例子中,我們定義了一個通用的模板類 Pair,包含兩個類型參數 TU。然后我們使用偏特化對兩個類型參數相同的情況進行了特化。這意味著當我們創建 Pair<int, int> 這樣的實例時,將使用偏特化的定義,即 Pair<int, int> 類型將只有一個 int 類型的成員 element

總之,全特化是對完整的模板進行特化,將所有參數都替換為具體的類型或值;而偏特化是對模板中的部分參數進行特化,允許我們為特定的參數組合提供不同的定義。這兩種特化形式使得C++中的模板更加靈活和強大。

通過模板偏特化獲取類型所占字節數

偏特化加可變參數

#pragma once
#include <iostream>
using namespace std;//泛化
template<class T,class ... ParamTypes>
class Flen
{
public:enum{Number = Flen<T>::Number + Flen<ParamTypes...>::Number//得到最終類型大小};
};//偏特化
template<class Last>
class Flen<Last>
{
public:enum{Number = sizeof(Last)};
};
#include <iostream>
#include"advanced.h"int main()
{Flen<int, float, double, int>len;//輸出結果位20 (4+4+8+4+4)cout << len.Number << endl;return 0;
}

通過模板偏特化和宏獲取類型所占字節數

…ParamTypes和ParamTypes…的區別

ParamTypes…:ParamTypes…將被展開為一系列類型參數,并傳遞給Flen模板的實例化
… ParamTypes:…是展開模板參數包的語法,而不是參數包本身的一部分。class … ParamTypes是用于展開模板參數包ParamTypes的語法

SpawnIndex<3, int, float, double>

在上面的代碼中,3 是一個非類型模板參數,int, float, double 是類型模板參數。在 SpawnIndex 的定義中,
…ParamTypes 將類型模板參數完整地展開,將 int, float, double 分別作為一個參數展開。
而 ParamTypes … 將 int, float, double 作為一個整體展開。

advanced.h

#pragma once
#include <iostream>
using namespace std;//泛化
template<class T,class ... ParamTypes>
class Flen
{
public:enum{Number = Flen<T>::Number + Flen<ParamTypes...>::Number//得到最終類型大小};
};//偏特化
template<class Last>
class Flen<Last>
{
public:enum{Number = sizeof(Last)};
};#define A(Name, ...)Flen<__VA_ARGS__>Name;//通過__VA_ARGS__接收

學習.cpp

#include <iostream>
#include"advanced.h"int main()
{Flen<int, float, double, int>len;//輸出結果位20 (4+4+8+4+4)cout << len.Number << endl;A(len2, int, float, double, int, long long);//輸出結果位28 (4+4+8+4+4+8)cout << len2.Number << endl;return 0;
}

通過繼承實現模板展開

using

using單獨使用相當于為類或結構體起別名

using Helloc = SpawnIndex<10>::Type;

給類Type起了別名Helloc

advanced.h

#pragma once
#include <iostream>
using namespace std;//定義
template<int ...>
struct HelloIndex 
{};//展開的中間值
template<int N,int ...ParamTypes>//N代表最大的,...ParamTypes代表數字
struct SpawnIndex :SpawnIndex<N - 1, N - 1, ParamTypes ...>
{};//終止,如果沒有此會無限循環
template<int ... ParamTypes>
struct SpawnIndex<0, ParamTypes ...>
{typedef HelloIndex<ParamTypes...>Type;
};

學習.cpp

#include <iostream>
#include"advanced.h"int main()
{using Helloc = SpawnIndex<10>::Type;//展開一個10,同時為類Type起了一個別名Helloc//using單獨使用相當于給類或結構體起別名//查看展開cout << typeid(Helloc).name() << endl;//輸出結果struct HelloIndex<0,1,2,3,4,5,6,7,8,9>SpawnIndex<3>::Type;//SpawnIndex<3>::Type;的展開過程// //匹配到struct SpawnIndex :SpawnIndex<N - 1, N - 1, ParamTypes ...>進行運算//struct SpawnIndex :SpawnIndex< 2, 2>//            //struct SpawnIndex< 2, 2> :SpawnIndex< 1, 1, 2>//                   N  ParamTypes      N  N  ParamTypes //左邊是template<int N,int ...ParamTypes>的形式,右邊是SpawnIndex<N - 1, N - 1, ParamTypes ...>// //struct SpawnIndex< 1, 1, 2> :SpawnIndex< 0, 0, 1, 2>//因為N值為0了,展開到這一步會終止,之后匹配struct SpawnIndex<0, ParamTypes ...>此模板,進行下面步驟// //typedef HelloIndex< 0, 1, 2>Type;return 0;
}

(ue4源碼的模板綜合了很多,如可變參數、特化、非特化)

通過using循環命名的方式來展開可變參數

advanced.h

#pragma once
#include <iostream>
using namespace std;//定義
template<int ...>
struct HelloIndex 
{};//通過using展開的中間值
template<int N, int ...ParamTypes>
struct SpawnIndex 
{using Type = typename SpawnIndex<N - 1,N - 1, ParamTypes...>::Type;//編譯器先發現Type,之后發現后面代碼,之后一層層遞歸,遞歸過程中參數會改變
};//循環終止
template<int ... ParamTypes>
struct SpawnIndex<0, ParamTypes ...>//最后在參數為0時運行最后模板
{typedef HelloIndex<ParamTypes...>Type;
};

學習.cpp

#include <iostream>
#include"advanced.h"int main()
{using Helloc = SpawnIndex<10>::Type;//查看展開cout << typeid(Helloc).name() << endl;//輸出結果:struct HelloIndex<0,1,2,3,4,5,6,7,8,9>return 0;
}

typename 是一個關鍵字,用于在模板編程中指示一個依賴類型。它通常用于聲明模板中的類型參數,用于告知編譯器某個名字代表一個類型

問題:為什么又兩個N-1
在模板參數SpawnIndex<N, int ...ParamTypes>中,N - 1在每次遞歸調用時作為新的模板參數傳遞給SpawnIndex,而N - 1, N - 1則是作為遞歸調用的模板參數。這兩個參數的作用如下:

首先,在每次遞歸調用時,N - 1作為新的模板參數傳遞給SpawnIndex<N - 1, N - 1, ParamTypes...>::Type,它用于更新N的值,實現遞減。這樣,在每次遞歸時,N的值都會減小,直到最后遞歸到SpawnIndex<0, ParamTypes...>,從而觸發遞歸終止的模板。

其次,在遞歸調用中,N - 1, N - 1作為ParamTypes的一部分被傳遞給遞歸調用的模板參數列表。這樣,新的模板參數列表中會包含N - 1, N - 1, ParamTypes...,并被傳遞給下一次遞歸調用。這樣,每次遞歸調用時,ParamTypes列表都會逐漸增長,記錄了調用的歷史信息。

綜上所述,N - 1主要用于控制遞歸調用的次數,而N - 1, N - 1在遞歸調用中記錄了每次遞歸的歷史信息。

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

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

相關文章

開發一個文生圖的功能

文章目錄 效果開發環境原理核心代碼代碼倉庫問題效果 開發環境 Python 3.10PyCharm原理 借助開源項目stable-diffusion,通過該項目封裝python庫diffusers,可以輕易的實現文生圖的功能。 關于更多diffusers的功能請訪問:https://huggingface.co/docs/diffusers/index 核心代…

css樣式表屬性

文章目錄 css樣式表屬性colorbackground-colorfont-sizefont-weightfont-familyfont-styletext-decorationtext-indentline-height(line-height的概念)width、heightletter-spacingtext-aligndirectionwriting-modefont-variantborder-radiusopacitycursorvertical-alignmin-wi…

【數據結構與算法】十大經典排序算法-歸并排序

&#x1f31f;個人博客&#xff1a;www.hellocode.top &#x1f3f0;Java知識導航&#xff1a;Java-Navigate &#x1f525;CSDN&#xff1a;HelloCode. &#x1f31e;知乎&#xff1a;HelloCode &#x1f334;掘金&#xff1a;HelloCode ?如有問題&#xff0c;歡迎指正&#…

如何用輸入函數為數組賦值

在編寫程序時我們經常使用數組&#xff0c;而數組的大小可能是很大的但是我們并不需要為每個元素都自己賦值&#xff0c;我們可能會自定義輸入數組元素個數&#xff0c;我們應該如何實現通過輸入函數為數組賦值呢&#xff1f; 目錄 第一種&#xff1a; 第二種&#xff1a; 第一…

大數據bug-sqoop(二:sqoop同步mysql數據到hive進行字段限制。)

一&#xff1a;sqoop腳本解析。 #&#xff01;/bin/sh mysqlHost$1 mysqlUserName$2 mysqlUserPass$3 mysqlDbName$4 sql$5 split$6 target$7 hiveDbName$8 hiveTbName$9 partFieldName${10} inputDate${11}echo ${mysqlHost} echo ${mysqlUserName} echo ${mysqlUserPass} ec…

OpenCV之remap的使用

OpenCV中使用remap實現圖像的重映射。 重映射是指將圖像中的某一像素值賦值到指定位置的操作&#xff1a;g(x,y) f ( h(x,y) )&#xff0c; 在這里&#xff0c; g( ) 是目標圖像, f() 是源圖像, 而h(x,y) 是作用于 (x,y) 的映射方法函數。為了完成映射過程, 需要獲得一些插值為…

TypeError: a bytes-like object is required, not ‘str‘

raceback (most recent call last): File "D:\pycharmcode\client.py", line 12, in <module> tcp_socket.send(send_data) TypeError: a bytes-like object is required, not str 使用socket進行ubuntu與windows通信時&#xff0c;發送數據時報了以上錯…

LeetCode 面試題 01.04. 回文排列

文章目錄 一、題目二、C# 題解 一、題目 給定一個字符串&#xff0c;編寫一個函數判定其是否為某個回文串的排列之一。 回文串是指正反兩個方向都一樣的單詞或短語。排列是指字母的重新排列。 回文串不一定是字典當中的單詞。 點擊此處跳轉題目。 示例1&#xff1a; 輸入&…

CSS3:圖片邊框

簡介 圖片也可以作為邊框&#xff0c;以下是實例演示 注意 實現該效果必須添加border樣式&#xff0c;且必須位于border-image-socure之前否則不會生效 實例 <html lang"en"><head><style>p {width: 600px;margin: 200px auto;border: 30px soli…

maven工具-maven的使用-鏡像倉庫、本地倉、IDEA使用maven

Maven 一、為什么使用maven 添加第三方jar包jar包之間的依賴關系處理jar包之間的沖突獲取第三方jar包將項目拆分成多個工程模塊實現項目的分布式部署 二、maven簡介 ? Maven項目對象模型(POM)&#xff0c;可以通過一小段描述信息來管理項目的構建&#xff0c;報告和文檔的…

2023.8 - java - 對象和類

public class Dog {String breed;int size;String colour;int age;void eat() {}void run() {}void sleep(){}void name(){} } 一個類可以包含以下類型變量&#xff1a; 局部變量&#xff1a;在方法、構造方法或者語句塊中定義的變量被稱為局部變量。變量聲明和初始化都是在方…

基于STM32標準庫智能風扇設計

目錄 一&#xff0c;前言 二&#xff0c;系統方案選擇 三&#xff0c;實體展示 工程分類 四&#xff0c;相關代碼 PWM.c PWM.h AD.c AD.h 電機驅動程序 舵機驅動 一&#xff0c;前言 當今生活中&#xff0c;風扇已成為人們解暑的重要工具&#xff0c;然而使用風扇緩解…

CentOS系統環境搭建(九)——centos系統下使用docker部署項目

centos系統環境搭建專欄&#x1f517;點擊跳轉 關于Docker-compose安裝請看CentOS系統環境搭建&#xff08;三&#xff09;——Centos7安裝Docker&Docker Compose&#xff0c;該文章同樣收錄于centos系統環境搭建專欄。 Centos7部署項目 采用前后端分離的形式部署。使用Do…

【Sklearn】基于隨機梯度下降算法的數據分類預測(Excel可直接替換數據)

【Sklearn】基于隨機梯度下降算法的數據分類預測(Excel可直接替換數據) 1.模型原理2.模型參數3.文件結構4.Excel數據5.下載地址6.完整代碼7.運行結果1.模型原理 隨機梯度下降(Stochastic Gradient Descent,SGD)是一種優化算法,用于訓練模型的參數以最小化損失函數。在分…

QT學習筆記-QT5.15編譯及安裝谷歌拼音輸入法(QtInputMethod_GooglePinyin)

QT學習筆記-QT5.15編譯及安裝谷歌拼音輸入法&#xff08;QtInputMethod_GooglePinyin&#xff09; 0、背景1、環境2、下載QtInputMethod_GooglePinyin源碼3、使用MinGW64構建套件編譯3.1 編譯QtInputMethod_GooglePinyin源碼3.2、部署tgtsmlInputContextPlugin輸入法插件3.3、運…

Lombok注解在JSON化中,JSON生成額外生成字段問題

問題描述&#xff1a; 定義如下對象 Dataclass A{private String A;public String getC() {return "abab";}} 執行如下邏輯 Autowiredprivate ObjectMapper objectMapper;Testpublic void test4() throws Exception {A a new A();a.setA("a");System.ou…

分布式 - 服務器Nginx:一小時入門系列之負載均衡

文章目錄 1. 負載均衡2. 負載均衡策略1. 輪詢策略2. 最小連接策略3. IP 哈希策略4. 哈希策略5. 加權輪詢策略 1. 負載均衡 跨多個應用程序實例的負載平衡是一種常用技術&#xff0c;用于優化資源利用率、最大化吞吐量、減少延遲和確保容錯配置。?使用 nginx 作為非常有效的HT…

【MySQL】如何使用Shared-memory協議(Windows)連接MySQL數據庫

文章目錄 【MySQL】如何使用Shared-memory協議(Windows)連接MySQL數據庫連接MySQL的協議使用Shared-memory協議(Windows)連接MySQL步驟1&#xff1a;確認MySQL服務器已啟用Shared-memory連接啟動Shared-memory連接方法 步驟2&#xff1a;客戶端使用shared-memory連接MySQL服務器…

神經網絡基礎-神經網絡補充概念-55-為什么是ML策略

“ML策略”&#xff08;Machine Learning Strategies&#xff09;是指在解決機器學習問題時&#xff0c;采取的一系列方法、技巧和策略。選擇適當的ML策略對于獲得高質量的模型和結果非常重要。以下是為什么要考慮ML策略的一些原因&#xff1a; 問題適應性&#xff1a;不同的機…

2023 最新版網絡安全保姆級指南,從 0 基礎進階網絡攻防工程師

一、網絡安全學習的誤區 1.不要試圖以編程為基礎去學習網絡安全 不要以編程為基礎再開始學習網絡安全&#xff0c;一般來說&#xff0c;學習編程不但學習周期長&#xff0c;且過渡到網絡安全用到編程的用到的編程的關鍵點不多。一般人如果想要把編程學好再開始學習網絡安全往…