一、命名模板參數:
有些高級腳本語言,如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 DefaultPolicy1 88 //Policies::P2 is class DefaultPolicy2 89 //Policies::P3 is class CustomPolicy 90 //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 1 45 //The count of MyClass is 2 46 //The count of MyClass is 1