C++ template 学习笔记(第十六章) 16.1 命名模版参数

第十六章标题就是 模版与继承,看到这个标题给我的第一反应就是蛋疼,模版和继承,对我来说这两个方面本身已经很复杂了,让它们进行结合....

不过人家不都是说么“有困难要学,没困难制造困难也要学!” 嗯,就是这个!通过周末两天的折腾,稍微看明白了一点思路,因此将这两天的所得写出来,希望大家一起学习,多多指教!

在许多模版技术中,往往需要模版带有几个长串的类型参数,并设有合理的缺省值,如下:

1 template <typename Policy1 = DefaultPolicy1,
2          typename Policy2 = DefaultPolicy2,
3          typename Policy3 = DefaultPolicy3,
4          typename Policy4 = DefaultPolicy4 >
5 class BreadSlicer
6 {
7 };

因此使用的时候只需 BreadSlicer<> 即可,不过如果需要指定某个特点的参数为非缺省值的时候,必须将前面的参数一一写出来(即便前面的几个参数仍为缺省值)。

如果将BreadSlicer< DefaultPolicy1, DefaultPolicy2, Custom > 可以实现为 BreadSlicer< Policy3 = Custom > 的方式,则会更加方便。
为了解决这个问题,我们主要考虑将缺省值放入一个基类中,通过继承、覆盖的方式来实现对特定参数的修改。

首先将缺省值集中到一个基类中:

1 class DefaultPolices
2 {
3 public:
4     typedef DefaultPolicy1 P1;
5     typedef DefaultPolicy2 P2;
6     typedef DefaultPolicy3 P3;
7     typedef DefaultPolicy4 P4;
8 };

为了防止多次继承这个基类,而产生二义性问题,因此我们采用虚拟继承:

class DefaultPolicyArgs : virtual public DefaultPolicies {};

为了对缺省值进行修改,我们通过辅助类,覆盖掉基类缺省值即可:

 1 template <typename Policy>
 2 class Polic1_is : virtual public DefaultPolicies {
 3     public:
 4         typedef Policy P1;            //改写缺省的 typedef
 5 };
 6 
 7 template <typename Policy>
 8 class Polic2_is : virtual public DefaultPolicies {
 9     public:
10         typedef Policy P2;            //改写缺省的 typedef
11 };
12 
13 template <typename Policy>
14 class Polic3_is : virtual public DefaultPolicies {
15     public:
16         typedef Policy P3;            //改写缺省的 typedef
17 };
18 
19 template <typename Policy>
20 class Polic4_is : virtual public DefaultPolicies {
21     public:
22         typedef Policy P4;            //改写缺省的 typedef
23 };

至此完成了对基类的处理,下面完成关于继承部分:

 1 //Discriminator<>产生4个不同的类,使PolicySelector 可以多次继承自相同的基类
 2 template < typename Base, int D >
 3 class Discriminator : public Base {
 4 };
 5 
 6 template <typename Setter1, typename Setter2, 
 7          typename Setter3, typename Setter4>
 8 class PolicySelector : public Discriminator<Setter1, 1>,
 9                     public Discriminator<Setter2, 2>,
10                     public Discriminator<Setter3, 3>,
11                     public Discriminator<Setter4, 4> {
12 };

上面部分完成了 PolicySelector 的设计部分,下面是使用部分:

 1 template <typename PolicySetter1 = DefaultPolicyArgs,
 2         typename PolicySetter2 = DefaultPolicyArgs,
 3         typename PolicySetter3 = DefaultPolicyArgs,
 4         typename PolicySetter4 = DefaultPolicyArgs>
 5 class BreadSlicer {
 6     typedef PolicySelector <PolicySetter1, PolicySetter2,
 7                         PolicySetter3, PolicySetter4>
 8             Poicies;
 9     //使用 Poicies::P1, Poicies::P2, Poicies::P3, Poicies::P4 来引用各个policies即可
10 }

至此完成了本次的任务。可以直接通过 BreadSlicer<Policy3_is<CustomPolicy> > bc; 直接设置第三个缺省值为 CustomPolicy
由于我们自始至终都没有对它们进行实例化,因此也不存在性能或者内存损耗的问题。

关于上面的实例中有两个关键点:
首先是 DefaultPolicies 类,通过虚拟继承解决了,由于DefaultPolicies被多次继承而产生二义性问题。
    在虚拟继承中如果多次继承同一个基类,则会只保存一份基类,因此,在以后调用中使用 Policy3_is<CustomPolicy>, Policy2_is<CustomPolicy>等,

    虽然在不同的类中修改,但是他们修改的都是同一份基类的成员,而最后的结果调用则同样是直接调用基类的成员,因此实现了对默认成员的修改。


其次是 Discriminator<Setter1, 1> 通过不同的模版参数,从而产生了几个不同的继承于同一个基类的类,在同时派生出 PolicySelector 形成钻石型虚拟多重继承,避免了直接从多个相同类型的基类继承。

原文地址:https://www.cnblogs.com/fanqs/p/Template_16_1.html