跟我学c++高级篇——模板元编程之三Policy续

一、基于原则设计

在前面分析了应用于元编程中的策略(Policy),为了更好的把策略和策略设计分析清楚,本文重点分析一下基于原则设计或者说基于策略的设计(policy-based)。在前面的分析说已经说明,策略更倾向于行为。所以, 基于原则设计是以Policy为基础,结合模板元编程的一种设计模式。

二、分析和template template parameters

在前面的策略分析中,看到了一种代码,即在模板内的模板参数又是模板的这种情况。类似于下面的代码:

template <class T>
struct OpNewCreator
{
  static T* Create()
  {
    return new T;
  }
};
//非模板做为模板参数
template <class CreationPolicy>
class WidgetManager:public CreationPolicy
{......};
//模板做为模板参数
template <template<class Created> calss CreationPolicy>
class WidgetManager:public CreationPolicy<Widget>
{......};
//used
typedef WidgetManager<OpNewCreator> MyWidgetMgr;
//而不是原来直接使用模板
typedef WidgetManager<OpNewCreator<Widget>> MyWidgetMgr;

在策略设计中,为了防止类型的清晰表达和安全控制,就可以使用template template parameters,如果单纯的使用模板,则容易让使用者产生错误的使用,也不容易理解(如上面的代码)。如果使用模板做为模板的参数,就会很清晰的让使用者明白策略的意义和目的。模板的模板参数的使用主要有两种方式,一种是模板类做为模板参数;另外一种是模板函数做为模板参数。上面举个模板类的例子,下面看一下模板函数的例子:

struct OpNewCreator
{
  template<Class T>
  static T * Create()
  {
    return new T;
  }
};

这种应用的目的其实是对早期编译器的一种兼容,但一般不再推荐。
使用策略的优势在于,利用policy classes可以更加灵活的形成接口,它是语法导向(Syntax Oriented)而非标记导向(Signature Oriented)。这就引出了它和继承的不同,继承是强规范型的,反复的继承会还会导致代码的膨胀甚至有可能造成代码的污染(不小心调用了没用实现的虚函数,产生了意想不到的后果)。而policy classes不然,它更松散,可以随机组成,它不会产生代码的膨胀(当然你要把模板的代码膨胀加进来也算),更安全。另外多重继承也缺乏具体的类型的信息,而在策略类的应用下,会明确的指定最终使用的策略的类的信息。
所以这就指出一个应用的方向,把二者结合起来,扬长避短。既可以动态的灵活的从外部更改policies又可以根据自己的的实际场景提供相关的policies。看上面的代码是不是有些熟悉,对,就是使用已经分析过的CRTP,不清楚的可以翻一翻前面的文章。

三、例程

经过上面的分析,可以看一个例程来加深一下印象:

#include <iostream>
#include <string>

template <typename OutputPolicy, typename LanguagePolicy>
class HelloWorld : private OutputPolicy, private LanguagePolicy {
 public:
  // Behavior method.
  void Run() const {
    // Two policy methods.
    Print(Message());
  }

 private:
  using LanguagePolicy::Message;
  using OutputPolicy::Print;
};

class OutputPolicyWriteToCout {
 protected:
  template <typename MessageType>
  void Print(MessageType&& message) const {
    std::cout << message << std::endl;
  }
};

class LanguagePolicyEnglish {
 protected:
  std::string Message() const { return "Hello, World!"; }
};

class LanguagePolicyGerman {
 protected:
  std::string Message() const { return "Hallo Welt!"; }
};

int main() {
  // Example 1
  using HelloWorldEnglish = HelloWorld<OutputPolicyWriteToCout, LanguagePolicyEnglish>;

  HelloWorldEnglish hello_world;
  hello_world.Run();  // Prints "Hello, World!".

  // Example 2
  // Does the same, but uses another language policy.
  using HelloWorldGerman = HelloWorld<OutputPolicyWriteToCout, LanguagePolicyGerman>;

  HelloWorldGerman hello_world2;
  hello_world2.Run();  // Prints "Hallo Welt!".
}

注:代码引自:https://en.wikipedia.org/wiki/Modern_C%2B%2B_Design#Policy-based_design

四、总结

在上一篇中,重点讲的是policy和policy class,而本篇重点是分析一下policy-based的用法,其实后者前者的一种综合的动用。元编程中的Policy-Based Class Design 既可以规避多重继承的缺点又可以利用模板技术的优点。这其实是给了一个编程的思维方式,要善于整合利用不同的技术来实现一个更优的方法。
工程创新也是创新。

猜你喜欢

转载自blog.csdn.net/fpcc/article/details/129197013