How can we implement the Builder design pattern using boost::mpl? [closed]

百般思念 提交于 2019-12-25 14:30:07

问题


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 ?

回答1:


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.



来源:https://stackoverflow.com/questions/13025279/how-can-we-implement-the-builder-design-pattern-using-boostmpl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!