template所代表的泛型程式設計是c++語言中的重要的組成部分,我將通過幾篇blog對這半年以來的學習做乙個系統的總結,本文是基礎篇的第二部分。
類模板tips
特化與偏特化
類模板也是公共邏輯的抽象,通常用來作為容器(例如:vector)或者行為(例如:clonable)的封裝。
下面定義了乙個printer類模板,負責列印以及轉化為string。
template
class
printer
string&&
to_string()
;//定義在內部
void
print()
private
: t t;};
//定義在外部
template
string&& printer::
to_string()
printer p(1
);//error
printer<
int> p(
1);//ok
與函式模板不同,類模板不能推斷例項化。所以你只能顯示指定型別引數使用printerp(1)
,而不能讓編譯器自行推斷printer p(1)
。
類模板的成員函式既可以定義在內部,也可以定義在外部。定義在內部的被隱式宣告為inline,定義在外部的類名之前必須加上template的相關宣告。我們還可以把類模板和函式模板結合起來,定義乙個含有成員函式模板的類模板。
template
class
printer
//成員函式模板
template
void
add_and_print
(const u& u)
;private
: t t;};
//注意這裡要有兩層template的說明
template
template
void printer::
add_and_print
(const u& u)
printer<
int> p(
42);p.
add_and_print
(1.1);
//自動推斷u為double,列印出43.1
template
class
printer
static
int s_value;
private
: t t;};
template
//注意這裡的定義方式
int printer
::s_value =1;
printer<
int>
pi(1)
;printer<
int>
pi2(1
);printer<
double
>
pd(1.0)
;pi.s_value +=1;
//pi和pi2中的改變了,pd的沒改變
其實這個結論是顯然的,static成員屬於例項化後的類,不同的例項化當然有不同static成員。就像上面的例子一樣,pi.s_value += 1
只影響到了printer
,而不會影響到printer
。
函式模板中的static區域性變數也有類似的工作方式。為了節省資源,類模板例項化時並不是每個成員函式都例項化了,而是使用到了哪個成員函式,那個成員函式才例項化。
template
class
printer
void
print()
private
: t t;};
class
empty
;empty e;
printer
p(e)
;//ok
雖然成員函式print無法通過編譯,但是因為沒有使用到,也就沒有例項化print,所以沒有觸發編譯錯誤。
為了簡化**,我們可以使用typedef為類模板的某個例項定義乙個別名,也可以使用using語句固定乙個或多個型別引數(這有點偏特化的意思了)。
typedef std:
:pair<
int,
int>
pairofint;
//ok,為std::pair定義了乙個別名
template using withnum = std:
:pairint>
;//ok,相當於定義了乙個std::pair的偏特化
pairofint poi;
//實際型別,std::pair
withnum:string> strs;
//實際型別,std::pair
withnum<
int>
ints;
//實際型別,std::pair
就像函式模板過載那樣,你可以通過特化(偏特化)類模板來為特定的型別指定你想要的行為。類模板的特化(偏特化)只需要模板名稱相同並且特化列表<>中的引數個數與原始模板對應上即可,模板引數列表不必與原始模板相同模板名稱相同。乙個類模板可以有多個特化,與函式模板相同,編譯器會自動例項化那個最特殊的版本。
template
//基本模板
classs}
;template<
>
//特化
class
s<
int> }
;template
//偏特化
class
s>};
template
//另外乙個偏特化
class
s<
t(u)
>};
intfunc
(int i)
s<
float
>
s1;s1.info()
;//呼叫base模板
s<
int>
s2;s2.info()
;//呼叫int特化版本
s<
float
*> s3;
s3.info()
;//呼叫t*特化版本
s<
decltype
(func)
> s4;
s4.info()
;//呼叫函式特化版本
提供了所有型別實參的特化是完全特化,只提供了部分型別實參或者t的型別受限(例如:t*)的特化被認為是不完整的,所以也被稱為偏特化。完全特化的結果是乙個實際的class,而偏特化的結果是另外乙個同名的模板。
除了可以特化類模板之外,還可以對類模板中的成員函式和普通靜態成員變數進行特化。
template
class
sstatic
int code;};
template
int s
::code =10;
template<
>
int s<
int>
::code =
100;
//普通靜態成員變數的int特化
template<
>
void s<
int>::
info()
s<
float
>
s1;s1.info()
;//普通版本
printf
("code is: %d\n"
, s1.code)
;//code = 10
s<
int>
s2;
s2.info()
;//int特化版本
printf
("code is: %d\n"
, s2.code)
;//code = 100
C Template 基礎篇(三) 引數魔法
template所代表的泛型程式設計是c 語言中的重要的組成部分,我將通過幾篇blog對這半年以來的學習做乙個系統的總結,本文是基礎篇的第三部分。除了使用型別作為模板的引數之外,模板引數有更多的用法,以下做個詳細介紹。我們可以通過給模板指定預設實參,為使用者推薦合適的預設設定,讓使用者在只指定部分 ...
python基礎學習筆記(二)類和物件
class bird object def init self,sound magic mehod 前後兩個下劃線 如 add self.sound sound dict print init sound sound def chirp self self 該函式可在同一類中被呼叫 print bi...
C 學習筆記(二)類和物件基礎
成員函式 注意 兩個冒號 int car size 函式size是car類的成員函式,只能通過物件 物件指標 物件引用才能呼叫。private 私有成員 public 公有成員 protected 保護成員 1 類成員函式的內部可訪問 當前物件和同類其他物件的全部屬性,函式。2 類的成員函式以外可訪...