一、命名模板參數:
有些進階指令碼語言,如Perl、PL/SQL等,他們的函數參數在調用時都支援具名引數,既在調用時可以不按照順序傳遞參數,而是p可以按照參數的名字傳遞。先看下面的程式碼範例:
template<typename Policy1 = DefaultPolicy1,
typename Policy2 = DefaultPolicy2,
typename Policy3 = DefaultPolicy3,
typename Policy4 = DefaultPolicy4>
class BreadSlicer {
... ...
}
上面的模板類含有4個模板參數,如果要想指定其中的某個參數不為預設參數,那麼也必須同時指定其之前的所有模板參數,如:
BreadSlicer<DefaultPolicy1,DefaultPolicy2,Custom>,然而我們更希望使用這樣的調用形式:BreadSlicer<Policy3 = Custom>。下面將給出一些具體的實現,請務必留意代碼中的關鍵性注釋:
1 #include <stdio.h> 2 #include <typeinfo> 3 #include <conio.h> 4 5 //先定義出不同的策略類。 6 class DefaultPolicy1 {}; 7 class DefaultPolicy2 {}; 8 class DefaultPolicy3 {}; 9 class DefaultPolicy4 {};10 11 //該類將會是所有Policy Class的基類。他提供了預設的四個Policy的類型重定義。12 //因此在預設情況下,這四個Policy將會是BreadSlicer的四個Policy。13 class DefaultPolicies {14 public:15 typedef DefaultPolicy1 P1;16 typedef DefaultPolicy2 P2;17 typedef DefaultPolicy3 P3;18 typedef DefaultPolicy4 P4;19 };20 21 //這裡之所以給出中間類DefaultPolicyArgs,同時又讓該類以虛擬繼承的方式繼承22 //DefaultPolicies,一是為了避免後面在多重繼承同一基類時而導致的二義性,同時23 //也是為了方便後面其他類的繼承。24 class DefaultPolicyArgs : virtual public DefaultPolicies {25 };26 27 //這裡之所以有第二個常量模板參數,是為了避免重複繼承相同的基類。28 template<typename Base, int D>29 class Discriminator : public Base {30 };31 32 //在這裡,如果沒有Discriminator的常量模板參數,將極有可能導致繼承同一個基類。33 template<typename Setter1, typename Setter2, 34 typename Setter3, typename Setter4>35 class PolicySelector : public Discriminator<Setter1,1>,public Discriminator<Setter2,2>, 36 public Discriminator<Setter3,3>, public Discriminator<Setter4,4> {37 };38 39 template<typename PolicySetter1 = DefaultPolicyArgs,40 typename PolicySetter2 = DefaultPolicyArgs,41 typename PolicySetter3 = DefaultPolicyArgs,42 typename PolicySetter4 = DefaultPolicyArgs>43 class BreadSlicer {44 public:45 //在該類後面的實現中,不要直接使用模板參數,而是要使用Policies::P1, P2, P3, P4等。46 typedef PolicySelector<PolicySetter1,PolicySetter2,PolicySetter3,PolicySetter4> Policies;47 void DoTest() {48 printf("Policies::P1 is %s\n",typeid(Policies::P1).name());49 printf("Policies::P2 is %s\n",typeid(Policies::P2).name());50 printf("Policies::P3 is %s\n",typeid(Policies::P3).name());51 printf("Policies::P4 is %s\n",typeid(Policies::P4).name());52 }53 };54 55 template<typename Policy>56 class Policy1_is : virtual public DefaultPolicies {57 public:58 typedef Policy P1; //改寫DefaultPolicies中的基於P1的typedef。59 };60 61 template<typename Policy>62 class Policy2_is : virtual public DefaultPolicies {63 public:64 typedef Policy P2; //改寫DefaultPolicies中的基於P2的typedef。65 };66 67 template<typename Policy>68 class Policy3_is : virtual public DefaultPolicies {69 public:70 typedef Policy P3; //改寫DefaultPolicies中的基於P3的typedef。71 };72 73 template<typename Policy>74 class Policy4_is : virtual public DefaultPolicies {75 public:76 typedef Policy P4; //改寫DefaultPolicies中的基於P4的typedef。77 };78 79 class CustomPolicy {};80 81 int main() {82 BreadSlicer<Policy3_is<CustomPolicy> > bc;83 bc.DoTest();84 getch();85 return 0;86 }87 //Policies::P1 is class DefaultPolicy188 //Policies::P2 is class DefaultPolicy289 //Policies::P3 is class CustomPolicy90 //Policies::P4 is class DefaultPolicy4
在上面的例子中一個非常重要的特點是,所有的模板實參都是DefaultPolicies的衍生類別。在聲明BreadSlicer對象時,不同的衍生類別將覆蓋不同的DefaultPolicies中的typedef。
二、遞迴模板模式:
這是一種通用的模板設計模式,即衍生類別將本身作為模板參數傳遞給基類,如:
template<typename DerivedT>
class Base {
... ...
};
class MyDerived : public Base<MyDerived> {
... ...
};
基於這種模式,有一個非常著名的用例,即[MeyersCounting],是《Effective C++》的作者Scott Meyers所設計的。通過繼承以下代碼中的基類,所有的衍生類別便可實作類別執行個體計數的功能。在下面的基類中,將包含一個表示對象計數的靜態成員,同時還會在基類構造的時候遞增該值,並在析構的時候遞減該值,見如下程式碼範例:
1 #include <stdio.h> 2 #include <conio.h> 3 4 template<typename CountedType> 5 class ObjectCounter { 6 private: 7 static size_t count; 8 9 protected:10 ObjectCounter() {11 ++ObjectCounter<CountedType>::count;12 }13 ObjectCounter(ObjectCounter<CountedType> const&) {14 ++ObjectCounter<CountedType>::count;15 }16 ~ObjectCounter() {17 --ObjectCounter<CountedType>::count;18 }19 20 public:21 static size_t liveCount() {22 return ObjectCounter<CountedType>::count;23 }24 };25 26 template<typename CountedType>27 size_t ObjectCounter<CountedType>::count = 0;28 29 //C++編譯器會根據模板參數的不同執行個體化不同類型的類對象,因此模板參數不同,所使用的靜態成員也是不同的。30 class MyClass : public ObjectCounter<MyClass> {31 };32 33 int main() {34 MyClass mc1;35 printf("The count of MyClass is %d\n",MyClass::liveCount());36 {37 MyClass mc2;38 printf("The count of MyClass is %d\n",MyClass::liveCount());39 }40 printf("The count of MyClass is %d\n",MyClass::liveCount());41 getch();42 return 0;43 }44 //The count of MyClass is 145 //The count of MyClass is 246 //The count of MyClass is 1