0

同じ概念クラスに準拠しているが、ストレージに使用される基礎となるデータ構造が異なる 3 つのクラスがあります。例として、以下に示す 3 つのクラスを取り上げます。

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>クラス A の完全な特殊化の使用を避けるために、 を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 は Container をモデル化しないため、一部のクラス メソッドの実装は vector クラスとは異なります。complexUDT 基底クラスは、他の 2 つのクラスとは大きく異なりますが、いくつかの小さなコード セグメントが共通しています。しかし、現在のリファクタリング アプローチでは、依然としてコードの冗長性が生じます。概念クラスで言及されているすべてのメソッドは、それぞれの実装で実装する必要があります。

だから私の質問は2つあります。

  1. boost::mpl を使用してビルダー デザイン パターンを実装するにはどうすればよいでしょうか。
  2. 上記の例で CRTP は何らかの形で役立ちますか?
4

1 に答える 1

1

あなたが何をしたいのかを正しく理解していれば、これでうまくいくかもしれません:

まず、すべてのコンテナーが同じインターフェースを実装する必要があります。必要に応じてアダプターを作成します (たとえば、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
};

ストレージ タイプに基づくコンストラクターが必要なため、ストレージ テンプレートはインスタンス化を管理する必要があります。

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

これにより、冗長コードのほとんどが削減されます。これがあなたが探しているものでない場合は、解決したい問題のより具体的な例が必要です.

于 2012-10-23T10:07:30.727 に答える