欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++模板非類(lèi)型形參的詳細(xì)講解

 更新時(shí)間:2021年11月17日 09:59:55   作者:Jerish_C  
這篇文章主要給大家介紹了關(guān)于C++模板非類(lèi)型形參的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作就有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

前言

關(guān)于模板的非類(lèi)型形參,網(wǎng)上有很多內(nèi)容,C++primer只有大概一頁(yè)的闡述,但是都不夠清晰詳細(xì)。下面我盡可能從自己的角度去給大家描述一下非類(lèi)型形參的相關(guān)細(xì)節(jié)。如果想進(jìn)一步理解非類(lèi)型形參以及模板內(nèi)容可以閱讀C++template這本書(shū),在4.1節(jié),8.3.3節(jié),13.2節(jié)都有相關(guān)解釋。

模板除了定義類(lèi)型參數(shù),我們還可以在模板定義非類(lèi)型參數(shù)。

什么是非類(lèi)型形參?顧名思義,就是表示一個(gè)固定類(lèi)型的常量而不是一個(gè)類(lèi)型。

先舉一個(gè)簡(jiǎn)單的例子(模板類(lèi)與模板函數(shù)都可以用非類(lèi)型形參)

//例子1:
template<class T,int MAXSIZE> class List{
      private:
         T elems[MAXSIZE];  
      public:
         Print(){ cout<<"The maxsize of list is"<<MAXSIZE; }
}
List<int,5> list;
list.Print();//打印"The maxsize of list is 5"

這個(gè)固定類(lèi)型是有局限的,只有整形,指針和引用才能作為非類(lèi)型形參,而且綁定到該形參的實(shí)參必須是常量表達(dá)式,即編譯期就能確認(rèn)結(jié)果。

這里要強(qiáng)調(diào)一點(diǎn),我們對(duì)于非類(lèi)型形參的限定要分兩個(gè)方面看

1.對(duì)模板形參的限定,即template<>里面的參數(shù)

2.對(duì)模板實(shí)參的限定,即實(shí)例化時(shí)<>里面的參數(shù)

下面逐個(gè)解釋一下非類(lèi)型形參的局限

1.浮點(diǎn)數(shù)不可以作為非類(lèi)型形參,包括float,double。具體原因可能是歷史因素,也許未來(lái)C++會(huì)支持浮點(diǎn)數(shù)。

2.類(lèi)不可以作為非類(lèi)型形參。

3.字符串不可以作為非類(lèi)型形參

4.整形,可轉(zhuǎn)化為整形的類(lèi)型都可以作為形參,比如int,char,long,unsigned,bool,short(enum聲明的內(nèi)部數(shù)據(jù)可以作為實(shí)參傳遞給int,但是一般不能當(dāng)形參)

5.指向?qū)ο蠡蚝瘮?shù)的指針與引用(左值引用)可以作為形參

下面解釋一下非類(lèi)型實(shí)參的局限

1.實(shí)參必須是編譯時(shí)常量表達(dá)式,不能使用非const的局部變量,局部對(duì)象地址及動(dòng)態(tài)對(duì)象

2.非Const的全局指針,全局對(duì)象,全局變量(下面可能有個(gè)特例)都不是常量表達(dá)式。

3.由于形參的已經(jīng)做了限定,字符串,浮點(diǎn)型即使是常量表達(dá)式也不可以作為非類(lèi)型實(shí)參

備注:常量表達(dá)式基本上是字面值以及const修飾的變量

//例子2:
template<class T,int MAXSIZE> class List{
private:
	T elems[MAXSIZE];  
public:
	void Print(){ cout<<"The maxsize of list is "<<MAXSIZE; }
};
 
const int num1 = 9; ;//全局變量
static int num2= 9; ;//全局變量
const int num3 = 9; ;//局部變量
 
List<int,num1> list; //正確
List<int,num2> list; //錯(cuò)誤
List<int,num3> list; //正確
 
//再看一個(gè)關(guān)于指針和字符串比較特別的例子
//例子3:
template<char const* name>
class pointerT{
 
};
 char a[] = "saaa";;//全局變量
 char a2[] = "saaa";;//局部變量,寫(xiě)在main函數(shù)里面
 char *b = "saaa";//全局變量
 char *const c = "saaa";//全局變量,頂層指針,指針常量
 
 
pointerT<"testVarChar">  p1;//錯(cuò)誤
 
pointerT<a>  p2;//正確
pointerT<a2>  p22;//錯(cuò)誤,局部變量不能用作非類(lèi)型參數(shù)
pointerT<b>  p3;//錯(cuò)誤,error C2975:“pointerT”的模板參數(shù)無(wú)效,應(yīng)為編譯時(shí)常量表達(dá)式
pointerT<c>  p4;//錯(cuò)誤,error C2970: “c”: 涉及帶有內(nèi)部鏈接的對(duì)象的表達(dá)式不能用作非類(lèi)型參數(shù)

//關(guān)于指針常量和常量指針可以參考博客

Const用法總結(jié)(快速區(qū)分指針常量與常量指針)

這里大家可能會(huì)有幾個(gè)疑問(wèn)

①.到底為什么字符串不能作為實(shí)參?

答:我們看到上面p1的模板實(shí)參是"testVarChar",然而當(dāng)我們?cè)诹硪粋€(gè)編譯單元(.cpp文件)同樣聲明這么一個(gè)模板實(shí)例時(shí),這兩個(gè)"testVarChar"的地址可能是不同的,編譯器傳遞給模板時(shí)就會(huì)傳遞傳遞不同的地址,從而導(dǎo)致這兩個(gè)模板實(shí)例是兩個(gè)不同且不兼容的類(lèi)型。這就是支持字符串的問(wèn)題所在。(這里可能更深的涉及模板的實(shí)現(xiàn)原理)

②.變量b和c作為模板實(shí)參為什么錯(cuò)誤不同?

答:首先解釋b實(shí)參,b在這里看做是一個(gè)指針,是一個(gè)全局指針,但是他不是一個(gè)常量表達(dá)式,所以b不對(duì)。我們?cè)倏纯碿,c相比于b對(duì)了一個(gè)const修飾符,表示這個(gè)指針是一個(gè)常量。然而const是一個(gè)比較特別的關(guān)鍵字,他具有內(nèi)部鏈接屬性(關(guān)于內(nèi)連接參考博客 理解C++的鏈接:C++內(nèi)鏈接與外鏈接的意義),也就是說(shuō)僅在定義這個(gè)變量的文件內(nèi)可見(jiàn),不會(huì)造成不同編譯單元的混編時(shí)的鏈接錯(cuò)誤。

這個(gè)特性對(duì)于模板來(lái)說(shuō)可是有問(wèn)題的,就像問(wèn)題①所描述的,由于每個(gè)編譯單元可能都有一個(gè)c變量,導(dǎo)致在編譯時(shí),實(shí)例化多個(gè)c,而且c的地址還不同,這就造成二個(gè)模板的實(shí)例是兩個(gè)不同且不兼容的類(lèi)型。

③為什么a變量作為實(shí)參可以?

答:我看過(guò)一些書(shū)籍,上面舉得例子都是用const修飾不行的情況下在加extern來(lái)形成extern constchara[]="saaa";這樣形式的語(yǔ)句,extern和const聯(lián)合使用確實(shí)可以壓制const的內(nèi)部屬性。

這個(gè)a這里可以看做一個(gè)數(shù)組類(lèi)型,進(jìn)一步理解數(shù)組與指針的關(guān)系

附:char * itoa(int, char *, int); 第二個(gè)參數(shù)明明是char*,為什么卻又不能是“char*”?

Itoa這個(gè)函數(shù)大家應(yīng)該多多少少接觸過(guò),它的功能使把一個(gè)整型按照你給的進(jìn)制轉(zhuǎn)換成你想要的字符串,也就是這個(gè)函數(shù)讓我覺(jué)得有必要再去研究一下字符串?dāng)?shù)組和字符串指針的區(qū)別。

首先看itoa這個(gè)函數(shù)原型,char * itoa(int originNum, char * targetStr, int standard);

第一個(gè)參數(shù)你的整型數(shù)據(jù),第二個(gè)是一個(gè)字符串,第三個(gè)是一個(gè)int型表示N進(jìn)制。

現(xiàn)在我們測(cè)試一下,

char *str=“hello”;

int num=123;

_itoa_s(num, str,10); //vs C++下使用會(huì)提示編譯錯(cuò)誤

itoa(num,str,10);//codeblocks下運(yùn)行會(huì)崩潰,正常環(huán)境下都會(huì)崩潰的

char str2[]=“hello”;

itoa(num, str2,10);//運(yùn)行正常

這樣我們發(fā)現(xiàn)明明函數(shù)原型的參數(shù)就是char*,為什么我們寫(xiě)的str卻不行呢?

char *和char[]到底有什么區(qū)別?

這里,我們先從其本質(zhì)說(shuō)起。說(shuō)到底一個(gè)是數(shù)組一個(gè)是指針,兩者其實(shí)除了都能保存字符串外區(qū)別確實(shí)大了。最重要的一點(diǎn)區(qū)別就是內(nèi)存分配(關(guān)于C語(yǔ)言變量在內(nèi)存的存儲(chǔ)位置,大家可以參考…….),對(duì)于基本類(lèi)型的單個(gè)變量與數(shù)組我們都會(huì)為其在棧上申請(qǐng)空間來(lái)存放數(shù)據(jù),而指針只是指向一塊內(nèi)存的索引,所以char*聲明的只是指向常量區(qū)”hello”的指針。

這時(shí)候我們?cè)倏匆幌耰toa的功能,它是要把num轉(zhuǎn)換成字符串存在str里面,然而這時(shí)候我們的str根本沒(méi)有一塊可以用的內(nèi)存,當(dāng)然會(huì)崩潰。

反觀數(shù)組str2,在聲明的時(shí)候就已經(jīng)在棧上分配內(nèi)存了,這時(shí)候當(dāng)然可以保存數(shù)據(jù)了。

因此,必須要為其分配內(nèi)存

char *t;

t = (char*)malloc(9*sizeof(char));

接著上面的例子,我們需要理解

char *str=“hello”;

char str2[]=“hello”;

這是兩種不同的操作,str是聲明一個(gè)指針指向常量區(qū)的”hello”。而str2是聲明一個(gè)str2數(shù)組用來(lái)存放一個(gè)”hello”字符串的拷貝??傊绻鹲tr動(dòng)態(tài)申請(qǐng)內(nèi)存的話,那么在堆里str指向的位置就會(huì)有一個(gè)”hello”,棧里面有str2指向的”hello”,常量區(qū)還有一個(gè)”hello”。雖然都是賦值,差距卻非常大。

下面一個(gè)例子進(jìn)一步證明了這一點(diǎn)(vs2012):

const char*s1= "sa1";

const char*s2= "sa1";

if(s1== "sa1")

{

         cout<<"ok";//打印ok

}

 

char *oname= (char*)malloc(6*sizeof(char));         

strcpy_s(oname,6,"hello");

cout<<oname;//打印hello

if(oname== "hello")

{

         cout<<oname;//不執(zhí)行

}

 

char str2[]= "hello";

cout<<str2;//打印hello

if(str2== "hello")

{

         cout<<str2;//不執(zhí)行

}

我們知道字符串比較不能用 == 直接比較,需要用strcmp,因?yàn)樯厦娴膕1,s2,oname,str2都是指針,比較其實(shí)只是比較指針的大小。我們看到,只有上面的 s1 == "sa1"結(jié)果是true。因?yàn)閟1,s2指向的都是常量區(qū)的“sa1”字符串。oname,str2分別指向堆和棧區(qū)。

那么我們看到他不僅避免了①中的實(shí)例化地址不同的問(wèn)題(因?yàn)槭侨治ㄒ坏模疫€避免了const帶來(lái)的內(nèi)部鏈接問(wèn)題,所以這一項(xiàng)可能是經(jīng)過(guò)編譯器優(yōu)化過(guò)的結(jié)果。

總結(jié)

到此這篇關(guān)于C++模板非類(lèi)型形參的文章就介紹到這了,更多相關(guān)C++模板非類(lèi)型形參內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用opencv拉伸圖像擴(kuò)大分辨率示例

    使用opencv拉伸圖像擴(kuò)大分辨率示例

    這篇文章主要介紹了使用opencv拉伸圖像擴(kuò)大分辨率示例,需要的朋友可以參考下
    2014-04-04
  • Qt在線安裝加速的實(shí)現(xiàn)

    Qt在線安裝加速的實(shí)現(xiàn)

    本文主要介紹了Qt在線安裝加速的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • C語(yǔ)言左旋轉(zhuǎn)字符串與翻轉(zhuǎn)字符串中單詞順序的方法

    C語(yǔ)言左旋轉(zhuǎn)字符串與翻轉(zhuǎn)字符串中單詞順序的方法

    這篇文章主要介紹了C語(yǔ)言左旋轉(zhuǎn)字符串與翻轉(zhuǎn)字符串中單詞順序的方法,給出了相關(guān)的兩道算法題目作為例子,需要的朋友可以參考下
    2016-02-02
  • Dev-C++調(diào)試方法的具體使用

    Dev-C++調(diào)試方法的具體使用

    本文主要介紹了Dev-C++調(diào)試方法的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • C語(yǔ)言將日期、時(shí)間保存到文本文件中的方法

    C語(yǔ)言將日期、時(shí)間保存到文本文件中的方法

    這篇文章主要給大家介紹了關(guān)于C語(yǔ)言將日期、時(shí)間保存到文本文件中的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C語(yǔ)言具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • c++創(chuàng)建二維動(dòng)態(tài)數(shù)組與內(nèi)存釋放問(wèn)題

    c++創(chuàng)建二維動(dòng)態(tài)數(shù)組與內(nèi)存釋放問(wèn)題

    這篇文章主要介紹了c++創(chuàng)建二維動(dòng)態(tài)數(shù)組與內(nèi)存釋放問(wèn)題,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-06-06
  • C++中using的三種用法舉例詳解

    C++中using的三種用法舉例詳解

    最近在使用中,發(fā)現(xiàn)了一種以前沒(méi)學(xué)過(guò)的using用法,于是在這里,將using的幾種用法總結(jié)一下,下面這篇文章主要給大家介紹了關(guān)于C++中using的三種用法,需要的朋友可以參考下
    2023-02-02
  • C連接Mysql數(shù)據(jù)庫(kù)代碼

    C連接Mysql數(shù)據(jù)庫(kù)代碼

    使用C語(yǔ)言連接Mysql數(shù)據(jù)庫(kù)的方法,大家可以看看
    2013-11-11
  • C++深入分析內(nèi)聯(lián)函數(shù)的使用

    C++深入分析內(nèi)聯(lián)函數(shù)的使用

    為了消除函數(shù)調(diào)用的時(shí)空開(kāi)銷(xiāo),C++ 提供一種提高效率的方法,即在編譯時(shí)將函數(shù)調(diào)用處用函數(shù)體替換,類(lèi)似于C語(yǔ)言中的宏展開(kāi)。這種在函數(shù)調(diào)用處直接嵌入函數(shù)體的函數(shù)稱為內(nèi)聯(lián)函數(shù)(Inline Function),又稱內(nèi)嵌函數(shù)或者內(nèi)置函數(shù)
    2022-04-04
  • 基于Matlab實(shí)現(xiàn)繪制3D足球的示例代碼

    基于Matlab實(shí)現(xiàn)繪制3D足球的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用Matlab實(shí)現(xiàn)繪制3D足球,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Matlab有一定幫助,需要的可以參考一下
    2022-11-11

最新評(píng)論