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

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

问题描述

我有三个类,它们遵循相同的概念类,但在用于存储的底层数据结构上有所不同.以下面给出的三个类为例.

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
};

A 类是使用向量的泛型类.为避免使用vector,提供了A 类的完整特化,它使用boost::dynamic_bitset<> 作为底层存储.最后,B 类使用用户定义的数据类型作为存储.上面的设计导致了大量的代码冗余.为了消除这种冗余,我想到了使用 boost::mpl

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
 };

由于 boost::dynamic_bitset 不为容器建模,因此某些类方法的实现与向量类不同.complexUDT 基类与其他两个类非常不同,但确实有一些常见的小代码段.但是目前的重构方法仍然会导致代码冗余.概念类中提到的所有方法都必须在每个实现中实现.

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. 我们如何使用 boost::mpl 实现构建器设计模式?
  2. CRTP 在上面的例子中有任何帮助吗?

推荐答案

如果我正确理解你想要做什么,这可能对你有用:

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

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

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;
};

虽然通常不推荐这样做,但您可以将 dynamic_bitset 子类化以添加/修改功能.请注意,您不能以多态方式使用它,因为它缺少虚拟析构函数.确保它不在其他地方使用.

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;
};

使用示例:

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 实现 Builder 设计模式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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