2011-01-21 7 views
13

C++の高度な機能をしばらく使用せず、C++の知識をリフレッシュしています。 特質とポリシーベースのプログラミングというコンセプトは、私の周りを頭に浮かべるこのクラスのC++の特性例

私はそれを変更したいと思います。私はジェネリックコンテナを書いています。コンテナが特定の基本クラスから派生したクラスだけを格納するというポリシーを強制したいと思います。これは、ベクター境界外のアイテムにアクセスしようとすると、コンテナが(スローするのではなく)無効なオブジェクトを返すためです。

template <class T> 
class GenericContainer 
{ 
private: 
    typedef std::vector<T> TypeVect; 
    void addElement(const T& elem); 

    TypeVect m_elems; 

public: 
    unsigned int size() const; 
    T& elementAt(const unsigned int pos); 
    const T elementAt(const unsigned int pos) const; 
}; 

この汎用コンテナを「ContainerItem」クラスのサブクラスのみを含むように制限するにはどうすればよいですか?

+1

このための標準的な(C++ 0X)機能は 'テンプレート<クラスベース、派生クラス>構造体is_base_ofである' –

+0

is_base_ofはまた、今のためのC++ 0X支持 – Grizzly

答えて

12

にのみ与えられたタイプ「D」は、別のタイプ「B」(この実装はnice Guru Of The Week articleから取られた)継承する場合にインスタンス化することができる少しIsDerivedFromテンプレートを使用することができます。あなたは今でき

template<typename D, typename B> 
class IsDerivedFrom 
{ 
    static void Constraints(D* p) 
    { 
    B* pb = p; // this line only works if 'D' inherits 'B' 
    pb = p; // suppress warnings about unused variables 
    } 

protected: 
    IsDerivedFrom() { void(*p)(D*) = Constraints; } 
}; 

// Force it to fail in the case where B is void 
template<typename D> 
class IsDerivedFrom<D, void> 
{ 
    IsDerivedFrom() { char* p = (int*)0; /* error */ } 
}; 

を単に継承を使用してIsDerivedFromテンプレートをインスタンス化:

template <class T> 
class GenericContainer : public IsDerivedFrom<T, ContainerItem> 
{ 
    ... 
}; 

TContainerItemを継承する場合は、このコードはコンパイルのみ。

+0

+1行B * pb = p;これはコンパイルの制約を強調し、不要なクラスをコンパイルに失敗させます。 –

+1

しばらく私の頭を傷つけていたのですか...これは本当に美しいです!ありがとう! – skyeagle

5

boost::mplを使用すると、コンパイル時に型がベースから継承することをアサートできます。

"独自のロール" 非常に簡単です:

template <typename D, typename B> 
class is_derived_from { 
    class No { }; 
    class Yes { No no[2]; }; 

    static Yes Test(B*); 
    static No Test(...); 
public: 
    enum { inherits = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) }; 
    static bool is_derived() { return inherits; } 
}; 

私は、これはもともとGoTWから来たと思います。次に、あなたが必要とするのは、適切なアサートメカニズムです(コンパイル時間はおそらくより良いでしょう)。これに対する通常のやり方は、ネガティブサイズの配列をアサーションに失敗させるマクロを作成するか、1を渡すマクロを作成することです。

+0

を欠いているコンパイラのブーストとTR1に見出すことができます私はBOOSTを伴わないソリューションを求めています。私は "自分自身をロールバックする"方法を知りたい – skyeagle

+0

あなた自身のロールで更新されました。 – Flexo

3

私はコンセプトチェックを探していると思います。これはC++ 0xに組み込まれる予定でしたが、延期されました。 Boostライブラリcontain a libraryはコンセプトを管理するものですが、シンタックスキャンディではありません。

サイドノート:コンテナ内のオブジェクトのスライスに注意してください。基本クラスと派生クラスの両方をコンテナに格納する場合は、オブジェクト自体の代わりにポインタを使用します。

2

タイプ特性およびポリシーベースプログラミングは、異なるトピックです。型特性は、余分な情報(組み込み関数)を含むことができない既存の型および型に関する新しい情報を追加します。ポリシーベースの設計は、さまざまな方法でさまざまな動作を組み立てるためにクラスを設計する方法です。コンパイル時の状態パターンのようなものです。

関連する問題