模板與繼承之藝術——命名模板參數,繼承命名模板參數
一、命名模板參數
許多模板技術拖著一長串的類型參數,不過很多參數都設有合理的缺省值。
template<typename Policy1 = DefaultPolicy1,
typename Policy2 = DefaultPolicy2,
typename Policy3 = DefaultPolicy3,
typename Policy4 = DefaultPolicy4>
class BreadSlicer{};
但是如果我們需要指定某個非缺省實參,還必須明確的指定在它之前的所有實參,即使這些實參跟默認參數一致。
BreadSlicer<DefaultPolicy1, DefaultPolicy2, Custom>
如果我們能夠實現類似BreadSlicer<Policy3 = Custom>顯然更有效率。
思路是這樣的:
(1)將參數分派給一個叫做Policy3的東西管理,上面的“=”可以換成模板,將Custom作為模板實參傳遞進去。
這裡我們將Policy3換個名字Policy3_is,然後用Policy3_is<Custom>實現賦值。
(2)將默認實參合並在一起,並用新名字進行索引修改。
class DeafultPolicies{
public:
typedef DefaultPolicy1 P1;//DefaultPolicy1是具體類,P1是為了索引到該類型
typedef DefaultPolicy2 P2;
typedef DefaultPolicy3 P3;
typedef DefaultPolicy4 P4;
};
然後創建類似Policy3_is類進行管理。
template<typename Policy>
class Policy1_is :
virtual public DefaultPolicies{ //為什麼要虛繼承?待會揭曉
typedef Policy P1; //將P1從新賦值
};
template<typename Policy>
class Policy2_is : virtual public DefaultPolicies{
typedef Policy P2;
};
。。。//剩下的Policy3_is與Policy4_is類似
上面的四個類可以說是
修改器,那這些修改器要怎樣安裝,安裝到哪裡呢?要創建一個有四個“插槽”的“插座”。
在這之前首先解決一個問題,默認參數是什麼,根據上面的模式,默認參數應該也從DefaultPolicies繼承而來的。
class DefaultPolicyArgs : virtual public DefaultPolicies{};//默認實參
”插槽“在插入“修改器”之前應該是被默認實參占領所以,要將四個相同類型(默認實參)同時繼承到一個類裡面就需要使用一點小技巧。
template<typename Base, int D> //使用D將相同的類型編程不同類型,但是類的本質不變,還是子類繼承基類
class D : public Base{};
template<typename T1, typename T2, typename T3, typename T4>
class PolicySelector : public D<T1, 1>, public D<T2, 2>, public D<T3, 3>, public D<T4, 4>{};
此處需要多重繼承所以為了避免產生二義性,前面的“修改器”和默認參數都需要虛繼承
最後就是組裝默認參數。
template<typename PolicySetter1 =
DefaultPolicyArgs,
typename PolicySetter2 =
DefaultPolicyArgs,
typename PolicySetter3 =
DefaultPolicyArgs,
typename PolicySetter4 =
DefaultPolicyArgs>
class BreadSlicer{
typedef PolicySelector<PolicySetter1, PolicySetter2, PolicySetter3, PolicySetter4> Policies;
//使用Policies::P1索引第一個實參。
};
就可以直接BreadSlicer<Policy3_is<Custom> > bc;
下面是一個完整的例子。
#include <iostream>
#include <list>
using namespace std;
class DefaultPolicy1{};
class DefaultPolicy2{};
class DefaultPolicy3{
public:
void print()
{
cout << "我是默認參數3" << endl;
}
};
class DefaultPolicy4{};
class DefaultPolicies{ //將默認實參合並
public:
typedef DefaultPolicy1 P1;
typedef DefaultPolicy2 P2;
typedef DefaultPolicy3 P3;
typedef DefaultPolicy4 P4;
};
class DefaultPolicyArgs : virtual public DefaultPolicies{};
template <typename Policy>
class Policy1_is : virtual public DefaultPolicies{
public:
typedef Policy P1;
};
template<typename Policy>
class Policy2_is : virtual public DefaultPolicies{
public:
typedef Policy P2;
};
template<typename Policy>
class Policy3_is : virtual public DefaultPolicies{
public:
typedef Policy P3;
};
template<typename Policy>
class Policy4_is : virtual public DefaultPolicies{
public:
typedef Policy P4;
};
template<typename Base, int d>
class D : public Base{};
template<typename B1, typename B2, typename B3, typename B4>
class Selector : public D<B1, 1>, public D<B2, 2>, public D<B3, 3>, public D<B4, 4>{};
template <typename T1 = DefaultPolicyArgs,
typename T2 = DefaultPolicyArgs,
typename T3 = DefaultPolicyArgs,
typename T4 = DefaultPolicyArgs>
class BreadSlicer{
typedef Selector<T1, T2, T3, T4> Policies;
public:
void print(){
typename Policies::P3 p3; //使用其中一個參數類型的例子,
//就用的第三個參數來展示吧
p3.print();
}
};
class Print3{
public:
void print()
{
cout << "我是客戶參數3" << endl;
}
};
int main()
{
//BreadSlicer<> b;
BreadSlicer<Policy3_is<Print3> > b;
b.print();
return 0;
}
編輯整理:Claruarius,轉載請注明出處。