Как мы можем реализовать шаблон проектирования Builder, используя boost :: mpl?

У меня есть три класса, которые придерживаются одного и того же концептуального класса, но различаются по базовой структуре данных, используемой для хранения. В качестве иллюстрации возьмите три класса, приведенные ниже.

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<bool> предоставляется полная специализация класса А, которая использует boost::dynamic_bitset<> в качестве основного хранилища. Наконец, класс B использует пользовательский тип данных в качестве хранилища. Вышеуказанный дизайн приводит к большой избыточности в коде. Чтобы удалить эту избыточность, я подумал об использовании 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 очень отличается от двух других классов, но у него есть несколько небольших общих сегментов кода. Но текущий подход к рефакторингу все еще приводит к избыточности кода. Все методы, упомянутые в концептуальном классе, должны быть реализованы в каждой из реализаций.

Так что я мой вопрос в два раза.

  1. Как мы можем реализовать шаблон проектирования Builder, используя boost :: mpl?
  2. Поможет ли CRTP каким-либо образом в приведенном выше примере?

0

Решение

Если я правильно понимаю, что вы хотите сделать, это может сработать для вас:

Прежде всего, каждый контейнер должен реализовывать один и тот же интерфейс. При необходимости создайте адаптеры (например, для ComplexUDT):

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

Хотя обычно это не рекомендуется, вы можете создать подкласс dynamic_bitset для добавления / изменения функциональности. Просто знайте, что вы не можете использовать его полиморфно, потому что в нем нет виртуального деструктора. Убедитесь, что он не используется в другом месте.

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

Определите черты, чтобы связать типы с контейнерами:

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

Создайте шаблон, который реализует интерфейс для хранилища (без контейнера):

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

Поскольку вам нужны конструкторы, основанные на типе хранилища, шаблон Storage должен управлять созданием экземпляра:

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

Это должно уменьшить большую часть избыточного кода. Если это не то, что вы ищете, мне нужен более конкретный пример проблемы, которую вы хотите решить.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]