非型別模板引數

2021-09-30 13:08:43 字數 3700 閱讀 7525

這是《c++ templates》第四章的學習筆記。這一章和下一章可以看作是對前面介紹的函式模板和類模板的補充。

這章的主要內容包括:

非型別的類模板引數。

非型別的函式模板引數。

非型別模板引數的限制。

在具體介紹以前有比較說明一下什麼是非型別的模板引數。在前面簡單介紹函式模板和類模板的時候,我們都再三說明,模板的引數應該是型別。我們需要通過指定某種型別來例項化乙個模板。但是,在這一章,我們會看見一些值作為模板引數的情況。這裡著重強調型別和值的區別。正因為是值作為模板引數,這一章才顯得很特別。

一:非型別的類模板引數。

我認為類模板的非型別引數相當於乙個全域性常量的角色。書中舉了下面的例子來說明非型別的類模板。這一章通過重新定義乙個stack模板,要求使用乙個固定大小的陣列作為元素的容器,並且陣列的大小可以由模板的使用者自己定義。那麼,對於模板的設計者,就應該提供乙個介面使得使用者可以定義陣列的大小。這就需要用到非型別的類模板引數。下面的**能很好的解釋這個問題:

#include 

<

iostream

>

2#include 

<

string

>

3#include 

<

cstdlib

>

4#include 

<

stdexcept

>56

template

<

typename t, 

intmaxsize

>

7class

stack

2021

bool

isfull() 

const

24};

2526

template

<

typename t, 

intmaxsize

>

27stack

<

t, maxsize

>

::stack():numelems(0)

2831

32template

<

typename t, 

intmaxsize

>

33void

stack

<

t, maxsize

>

::push(t 

const

&elem)

3439

40elems[numelems] 

=elem;

41++

numelems;42}

4344

template

<

typename t, 

intmaxsize

>

45void

stack

<

t, maxsize

>

::pop()

4651

52--

numelems;53}

5455

template

<

typename t, 

intmaxsize

>

56t stack

<

t, maxsize

>

::top()

const

5762

63//

返回最後乙個元素。

64return

elems[numelems -1

];65}66

67int

main()

6884

catch

(std::exception 

const

&ex)

8590

91return0;

92}上面的**揭示了非型別的類模板引數的定義和使用方法。需要注意的有:

非型別的類模板引數也是模板的引數之一。有某個非型別的模板引數的模板和沒有那個非型別的模板引數的模板是兩個不同的模板。

上面的int20stack例項和int40stack例項中,雖然例項化模板的時候都使用了int作為型別引數。但是他們仍然是兩個不同的類的例項。他們之間沒有任何的關係。不能相互進行型別轉化,也不能賦值。這裡需要注意,類模板的例項化在實質上是編譯器將原來的模板拷貝乙份,然後根據例項化引數替換原來的型別定義(也包括非型別的模板引數),從而成為乙個新的類。也就是說,對於相同的例項化引數(包括非型別的模板引數)編譯器都會例項化成為乙個相同的類,只是我們不知道類名罷了。從這個角度上來說,上面的int20stack和int40stack是兩個不同類的兩個例項,他們之間沒有任何關係,因為他們的模板例項化引數不一樣。但是,如果定義為[stack

<

int, 

20>

intstack1;

stack

<

int, 

20>

intstack2;]那麼intstack1和intstack2可以相互賦值。因為他們對模板的例項化引數是一樣的,從而都是同一型別的。這裡有必要澄清乙個事實,如果兩個類有相同的成員函式和成員變數,他們生成的例項仍然是兩個型別,與這裡的情況完全不一樣。

非型別的類模板引數也可以有預設值。例如,template

<

typename t, 

intmaxsize

= 100>

...再一次強調,非型別的模板引數和型別模板引數一樣,也是標識乙個模板的因素之一。

二:非型別的函式模板引數。

函式模板的非型別引數主要用來為函式提供乙個運算常量。關於非型別的函式模板引數,書中有下面的例子:

//函式模板定義

2template

<

typename t, 

intval

>

3t addvalue(t 

const&x)

478//

其他**

91011

//函式模板的使用

12std::transform(source.begin(), source.end(), dest.begin(),13(

int(

*) (

intconst

&))addvalue

<

int, 

5>

);上面的**中定義了乙個函式模板,目的是對傳入的引數加上乙個指定的int型的5。這樣的函式被普遍的使用在對一組資料進行同一處理的場合。例如,12行。這裡需要注意的是:一

std::transform

函式本身就是乙個模板函式,它的最後乙個引數可以傳遞乙個函式指標。

因此,(

int(

*) (

intconst

&))addvalue

<

int, 

5>

其實是乙個指向例項化後的

addvalue

模板函式的指標。至於這個指標怎麼讀,還請高手指教。

另外需要注意的一點是,

std::transform

。只是模板函式更合適處理多種型別的資料罷了。

三:非型別模板引數的限制。

關於非型別模板引數的限制目前記住它可以是常整型(包括列舉型別)和指向外部連線物件的指標就可以可了。由於歷史原因,浮點型不能作為非型別模板的引數;而指標和字串作為非型別模板的引數是有條件的。我想這與變數的作用範圍和生命週期有關吧。書中後面會有比較相信的介紹,就等到時候再細看了。

C 非型別模板引數

對於函式模板與類模板,模板引數並不侷限於型別,普通值也可以作為模板引數。在基於型別引數的模板中,你定義了一些具體的細節來加以確定 直到 被呼叫時這些細節才被真正的確定。但是在這裡,我們面對的是這些細節是值,而不是型別,當要使用基於值的模板時,必須顯式地指定這些值,才能夠對模板進行例項化。在上篇文章 ...

C 非型別模板引數

對 於函式模板與類模板,模板引數並不侷限於型別,普通值也可以作為模板引數。在基於型別引數的模板中,你定義了一些具體的細節來加以確定 直到 被調 用時這些細節才被真正的確定。但是在這裡,我們面對的是這些細節是值,而不是型別,當要使用基於值的模板時,必須顯式地指定這些值,才能夠對模板進行例項 化。在上篇...

C 非型別模板引數

對於函式模板與類模板,模板引數並不侷限於型別,普通值也可以作為模板引數。在基於型別引數的模板中,你定義了一些具體的細節來加以確定 直到 被呼叫時這些細節才被真正的確定。但是在這裡,我們面對的是這些細節是值,而不是型別,當要使用基於值的模板時,必須顯式地指定這些值,才能夠對模板進行例項化。在上篇文章 ...