Posted on 2007-06-01 11:39
chemz 閱讀(1543)
評(píng)論(2) 編輯 收藏 引用 所屬分類:
C++
什么元素可以作為模板參數(shù)的實(shí)參
在C++中模板分為兩大類別:類模板和函數(shù)模板。這兩種類別的模板在語法形式上是相同
的,只是各自存在一些特別的約束。那么什么樣的C++元素可以作為實(shí)參來替換模板中的形參
呢?這里又主要分成兩大類實(shí)參類型:
1. 類型實(shí)參
類型實(shí)參實(shí)際上就是C++中間的各種各樣的數(shù)據(jù)類型,包括POD類型和類類型。比如:
char、int、int*、int&、float和用戶定義的類型。
2. 非類型實(shí)參
非類型實(shí)際上就是值的意思,而要作為模板實(shí)參的值就必須是一個(gè)常量值,更準(zhǔn)確
的說就必須是一個(gè)在編譯期能夠確定的值(簡稱編譯期常量),然而編譯期常量在
C++中包含了非常廣泛的概念,也不是所有的編譯期常量都可以作為模板的實(shí)參的,
也就是僅僅只有編譯期常量的一個(gè)子集可以作為模板實(shí)參,那么什么編譯期常量可
以作為模板實(shí)參呢?主要有三種類型的編譯期常量:
a. 整型常量
在C++中所謂的整型包括char、short、int、long、long long、上述類型的
無符號(hào)類型、wchar_t、enum類型。其中要注意的是float和double類型是不
可以作模板實(shí)參的(在C++0x標(biāo)準(zhǔn)中會(huì)改變這一狀況)。
b. 函數(shù)地址
函數(shù)地址主要包括非成員函數(shù)地址、成員函數(shù)地址、靜態(tài)成員函數(shù)地址。
c. 具有外部引用的字符串?dāng)?shù)組
什么是具有外部引用的字符串?dāng)?shù)組呢?就是具有如下形式:
extern char cstr[]; // 可以初始化,如:extern char cstr[] = ""
// char也可以是wchar_t
需要注意的是extern char *cstr;所聲名的是一個(gè)指針而不是一個(gè)數(shù)組,所
以不能夠用作模板的實(shí)參。那么在作為模板實(shí)參的時(shí)候是采用了cstr所包含
的字符串值作為模版實(shí)參的嗎,其實(shí)不是,雖然cstr是一個(gè)字符串,其實(shí)在
作為模板實(shí)參是僅僅用到了cstr的地址,也就是說如下的定義是合法的:
extern char cstr1[] = "cstr";
extern char cstr2[] = "cstr";
template<char *V> struct CTemplateValue {};
// 或者 template<char V[]> struct CTemplateValue {};
template<> struct CTemplateValue<cstr1> {};
template<> struct CTemplateValue<cstr2> {};
上面的代碼中,cstr1和cstr2都包含有相同的字符串值,但是在作為模板實(shí)參
時(shí)并沒有參考cstr1和cstr2的內(nèi)容,而是依賴于其地址,所以可以進(jìn)行模板的
特化,而不出現(xiàn)重復(fù)特化的編譯時(shí)錯(cuò)誤。
總的來說這里上面的三種常量都是編譯期常量,對(duì)于第一種情況是比較好理解的,而
對(duì)于第二三種請(qǐng)款可能就不那么直觀了,為什么函數(shù)地址和外部引用的字符串是編譯
期常量呢?首先我們來解釋一下編譯器在編譯函數(shù)和全局外部引用的變量時(shí)會(huì)如何處
理這兩者的地址,以使得其他的代碼或模塊能夠順利地找到該地址并調(diào)用函數(shù)或引用
變量。
首先可以肯定的是編譯器必須為函數(shù)和全局外部引用的變量生成唯一的入口地址,否
則就無法引用了;
其次編譯器會(huì)生成什么樣的地址呢?地址分為:物理地址(PA)和虛擬地址(RVA),
目前編譯器一般不會(huì)生成物理內(nèi)存地址的,因?yàn)榛旧纤械某绦蛟诓僮飨到y(tǒng)調(diào)度運(yùn)
行時(shí)均不可能保證該物理內(nèi)存地址可以被分配給該程序使用(可能已經(jīng)被其他的程序
占用了),那么現(xiàn)在的編譯器均會(huì)選擇生成RVA地址,其實(shí)RVA地址是相對(duì)于程序載入
首地址的一個(gè)偏移常量(offset),那么操作系統(tǒng)在載入程序時(shí)僅僅需要修改程序的
載入首地址就可以完成程序的載入,而程序內(nèi)部在調(diào)用一個(gè)函數(shù)或引用變量時(shí)會(huì)采用
首地址+RVA地址的方法來完成引用,這樣一來RVA就成為了一個(gè)編譯期的整型常量了,
所以函數(shù)地址和全局外部引用字符串的地址就成為了編譯期的常量,可以作為模板實(shí)
參了。那為什么必須是外部引用的字符串?dāng)?shù)組呢?內(nèi)部引用的字符串?dāng)?shù)組不可以么?
如果對(duì)此有興趣可以關(guān)注后續(xù)相關(guān)內(nèi)外部引用的討論blog。