我们如何使用boost :: MPL落实生成器设计模式? [英] How can we implement the Builder design pattern using boost::mpl?

查看:847
本文介绍了我们如何使用boost :: MPL落实生成器设计模式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有坚持不变的概念类,但在用于存储底层的数据结构不同三类。作为一个例证采取如下三大类。

 模板<类型名T>
A级{
  的std ::矢量< T>存储;
  //等等
};模板<>
类A<布尔> {
  提高::来,dynamic_bitset<>存储;
  //等等
};B类{
   ComplexUDT存储;
   //等等
};

A类是使用矢量泛型类。为了避免使用矢量&lt的;布尔> 提供A级的完整的专业化,它使用的boost ::来,dynamic_bitset<> 作为底层存储。最后,B类使用用户定义的数据类型作为存储。以上的设计导致code大量冗余。要消除这种冗余,我想使用boost :: MPL

 模板<类型名T>
类vec_impl {
   的std ::矢量< T>存储;
   //方法IMPL
};类bitset_impl {
   提高::来,dynamic_bitset<>存储;
   //方法IMPL
 }; 类udt_impl {
    ComplexUDT存储;
    //方法IMPL
 }; 模板<衍生,存储和GT;
 类main_class_gen {
     的typedef typename的提振:: MPL :: if_< is_complexudt<储存>中
                                      udt_impl,
                                      TYPENAME的boost :: MPL :: if_< is_bool<储存>中
                                                                bitset_impl,
                                                                vec_impl<存储和GT; > ::类型> :: type类型
 }; 类MAIN_CLASS:
                  公共main_class_gen< MAIN_CLASS<存储和GT;,存储和GT; :: {类型
        // implement执行。方法
 };

由于升压::,dynamic_bitset不模拟一个容器的一些类方法的实现比vector类不同。该complexUDT基础类是其他两个类大不相同,但也有共同的一些小code链段。但目前的重构方法仍然导致code冗余。在概念类提到的所有方法都在每一个实现中实现。

所以我我的问题是双重的。


  1. 我们如何使用boost :: MPL落实生成器设计模式?

  2. 应该CRTP帮助以任何方式在上面的例子?


解决方案

如果我理解正确,你希望做什么,这可能会为你工作:

首先,每个容器必须实现相同的接口。根据需要(为ComplexUDT例如)创建适配器:

 结构AdapterUDT {
  双的typedef为const_reference;
  无效的push_back(双);
  私人:ComplexUDT complexUDT;
};

虽然一般不推荐它,你可以继承来,dynamic_bitset添加/修改功能。要知道,因为它缺乏一个虚析构函数,你不能用它多态。确保它不会在别处使用。

 结构AdapterBitset:来,dynamic_bitset<> { // 不建议
  的typedef my_biterator迭代器;
  AdapterBitset(INT N):来,dynamic_bitset(N){}
  迭代开始();
};

定义性状类型的容器相关联:

 模板< typename的T>结构特质{
  typedef的矢量< T>类型;
};
模板<>结构特质<布尔> {
  的typedef来,dynamic_bitset<>类型;
};

创建一个实现了接口,为存储模板(减去容器):

 模板< T类,类派生的>结构基地{
  typedef的基地< T,衍生> base_t;
  的typedef typename的特质< T> ::类型CONTAINER_TYPE;
  的typedef typename的CONTAINER_TYPE ::为const_reference为const_reference;
  无效追加(价值为const_reference){
    //静态多态性访问标准化集装箱/适配器
    的static_cast<衍生*>(这) - GT; container.push_back(值);
  }
  //等
};

由于需要根据存储类型的构造函数,存储模板有管理实例:

 模板<类T>存储结构:基< T,存储和LT; T>> {
  朋友结构base_t;
  保护:CONTAINER_TYPE容器;
};
//为专门类型的构造函数参数:
模板<>结构存储和LT;布尔> :基地<布尔,存储和LT;布尔>> {
  朋友结构base_t;
  存储(INT位):容器(位){}
  保护:CONTAINER_TYPE容器;
};

用法示例:

 存储和LT; INT>一家商店; //通用版使用默认构造函数
astore.append(314);
存储和LT;布尔> bstore(7); //布尔专业化要求一个int
bstore.append(真);

这应该减少大多数冗余code的。如果这是不是你要找什么,我需要你想解决问题的更具体的例子。

I have three classes which adhere to the same concept class but differ on the underlying data structure used for storage. As an illustration take the three classes given below.

template< typename T >
class A{
  std::vector<T> storage;
  //etc
};

template<>
class A<bool>{
  boost::dynamic_bitset<> storage;
  //etc
};

class B{
   ComplexUDT storage;
   //etc
};

Class A is the generic class that uses a vector. To avoid the use of vector<bool> a full specialisation of class A is provided that uses the boost::dynamic_bitset<> as the underlying storage. Finally, Class B uses a user defined data type as storage. The above design leads to a lot of redundancy in code. To remove this redundancy I thought of using boost::mpl

template< typename T >
class vec_impl{
   std::vector< T >  storage;
   //impl of methods
};

class bitset_impl{
   boost::dynamic_bitset<> storage;
   //impl of methods
 };

 class udt_impl{
    ComplexUDT storage;
    //impl of methods
 };

 template<Derived,Storage>
 class main_class_gen{
     typedef typename boost::mpl::if_<is_complexudt<Storage>,
                                      udt_impl,
                                      typename boost::mpl::if_< is_bool<Storage>,
                                                                bitset_impl,
                                                                vec_impl<Storage> >::type >::type type
 };

 class main_class:
                  public main_class_gen< main_class<Storage>,Storage >::type{
        //impl. of methods
 };

As boost::dynamic_bitset does not model a Container the implementation of some of the class methods are different than the vector class. The complexUDT bases class is very different from the two other classes but do have some small code segements common. But the current refactoring approach still results in code redundancy. All the methods mentioned in the concept class have to implemented in the each of the implementations.

So I my question is two fold.

  1. How can we implement the Builder design pattern using boost::mpl ?
  2. Would CRTP help in any way in the above example ?

解决方案

If i understand correctly what you wish to do, this may work for you:

First of all, every containers must implement the same interface. Create adapters as needed (for ComplexUDT for example):

struct AdapterUDT {
  typedef double const_reference;
  void push_back( double );
  private: ComplexUDT complexUDT;
};

While it is generally not recommended, you could subclass dynamic_bitset to add/modify functionality. Just be aware that you cannot use it polymorphically because it lacks a virtual destructor. Ensure that it's not used elsewhere.

struct AdapterBitset : dynamic_bitset<> { // not recommended
  typedef my_biterator iterator;
  AdapterBitset( int n ) : dynamic_bitset(n) {}
  iterator begin();
};

Define traits to associate types with containers:

template<typename T> struct Trait {
  typedef vector<T> type;
};
template<> struct Trait<bool> {
  typedef dynamic_bitset<> type;
};

Create a template that implements the interface for the Storage (minus the container):

template<class T, class Derived> struct Base {
  typedef Base<T,Derived> base_t;
  typedef typename Trait<T>::type container_type;
  typedef typename container_type::const_reference const_reference;
  void append( const_reference value ) {
    // static polymorphism to access the standardized containers/adapters
    static_cast<Derived*>(this)->container.push_back(value);
  }
  // etc
};

Since you need constructors based on the storage type, the Storage template has to manage the instantiation:

template<class T> struct Storage : Base<T,Storage<T>> {
  friend struct base_t;
  protected: container_type container;
};
// specialize for types with ctor arguments:
template<> struct Storage<bool> : Base<bool,Storage<bool>> {
  friend struct base_t;
  Storage( int bits ) : container(bits) {}
  protected: container_type container;
};

Usage example:

Storage<int> astore; // generic version uses default ctor
astore.append(314);
Storage<bool> bstore(7); // bool specialization requires an int
bstore.append(true);

This should reduce most of the redundant code. If this isn't what you're looking for, i need a more concrete example of the problem you wish to solve.

这篇关于我们如何使用boost :: MPL落实生成器设计模式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆