2011-08-25 11 views
7

コンパイルされない次のコードがあります。インターフェイスオブジェクトを持つC++テンプレート

class Base { 
    public: 
     virtual ~Base() { }; 
}; 

class Derived : public Base { }; 

class NotDerived { }; 

template <typename T> 
class Group { }; 

int main() { 
    Group<Base> *g = NULL; 

    g = new Group<Base>();  // Works 
    g = new Group<Derived>(); // Error, but I want it to work 

    g = new Group<NotDerived>(); // Error, as expected 
} 

私はgGroup<Derived>とは異なるタイプであるため、これはコンパイルされませんことを理解しています。 Javaでこの作業を行うには、Group<? extends Base> gなどの処理を行いますが、C++にはわかっている限り、そのキーワードはありません。何ができますか?

編集:Baseから派生しないタイプをgとして設定したくないということを明確にしたいと思います。私はこれを説明するために私の例を更新しました。

編集2:私の問題は2つの解決策があります。 Dave's私は単純で簡単に定義することができました。しかし、Bowie's(加えてMark'sの追加)が私のニーズに適していました。

+0

私はこの種のことがJavaでどのように機能するかに慣れていません。あなたはその構文で何を言おうとしていますか? –

+0

これはJavaでも動作しません。 '<? extends ...> 'は共分散をサポートするためのものではありませんが、ジェネリックがどのタイプを使用するかという制約を加えることができます。 –

+0

[C++ template polymorphism](http://stackoverflow.com/questions/2203388/c-templates-polymorphism) – Praetorian

答えて

3

T> T!=ベース。

class Base { 
    public: 
     virtual ~Base() { }; 
}; 

class Derived : public Base { }; 


template <typename T> class Group; 

struct Empty { }; 

template <typename T> 
struct base_for_group_t { 
    typedef Group<Base> type; 
}; 

template <> 
struct base_for_group_t<Base> { 
    typedef Empty type; 
}; 

template <typename T> 
class Group : public base_for_group_t<T>::type { }; 

int main() { 
    Group<Base> *g = 0; 

    g = new Group<Base>(); // Works 
    g = new Group<Derived>(); // now works 
} 
+0

残念ながら、このようなものは正当です: 'class NotDerived {}; g =新しいグループ(); '。可能であればタイプの安全性を維持したいと思います。 – Ryan

1

私はC++をサポートしているとは思いません。 C++テンプレートはコンパイル時に完全に処理されるため、多型をサポートしていません。つまり、テンプレート引数の型は、代入式の両側で正確に同じでなければなりません。

0

C++テンプレートとJavaジェネリックは、正方形や円のように非常に異なっています。実行時の型が汎用コードブロック内で動作し一致することを検証するコードを生成します。非常に一言で言えば、

What are the differences between "generic" types in C++ and Java?

5

クラスGroup<Base>Group<Derived>は、異なるクラス完全に無関係です。それらへのポインタはどちらの方向にも変換できません。

あなたはランタイム・多形性行動が必要な場合は、あなたのクラステンプレートGroupが共通の(非テンプレート)基本クラスから派生することができます:あなたはグループ<ベース>すべてのグループ<の基底クラスを作ることができ

class Group // base 
{ 
    virtual ~Group() { } 
}; 

template <typename T> 
class ConcreteGroup : public Group 
{ 
    // ... 
    T * m_impl; 
}; 

Group * g1 = new ConcreteGroup<A>; 
Group * g1 = new ConcreteGroup<B>; 
+0

ConcreteGroupはグループを継承する必要はありませんか? –

+0

@Mu:はい、ありがとう、固定! –

2

Bowie Owens's Answer元の質問を解決するために必要な共分散を処理します。編集した質問であなたが求めた制約については、タイプ特性を使ってこれを達成することができます。

template <typename T, class Enable = void> class Group; 

template <typename T> 
class Group<T, typename enable_if<is_base_of<Base, T>::value>::type> 
    : public base_for_group_t<T>::type { }; 
+0

残念ながら、私はそれを私の目的のためにコンパイルすることはできません(私は正しくタイプ特性を使用する方法に慣れていません)。より完全な例を提供できますか? ( 'Group 'は 'template class Group'とされていましたが、これはうまくいきませんでした) – Ryan

+0

' (std :: enable_ifとstd :: enable_ifの間に必要な相違点)。 –

+0

ああ、私はstd名前空間を含んでいませんでした。 ;) – Ryan

0

私はあなたが行っていることを理解していると思います。私はそれが最良のアプローチであるとは確信していません(あなたはBoost.Factoryを見たいかもしれません)。

template <class T> 
class Factory { 

public: 
    virtual T* operator()() = 0; 
}; 

template <class Derived, class Base> 
class ConcreteFactory : public Factory<Base> { 

public: 
    virtual Base* operator()() { 
    return new Derived(); 
    } 
}; 

class Base { 
public: 
    virtual ~Base() {}; 
}; 

class Derived1 : public Base { }; 
class Derived2: public Base {}; 

class NotDerived {}; 

int main() 
{ 
    Factory<Base>* g; 

    g = new ConcreteFactory<Derived1, Base>; 
    g = new ConcreteFactory<Derived2, Base>; 
    // g = new ConcreteFactory<NotDerived, Base>; // Will not work if you try to do this 
} 
+0

これは、これまでの中で最も安全な解決策であるようです。 Derived1とBaseの両方の定義は少し冗長ですが、私がすでに知っていることは何もありません(そして私はtypedefで回避できます)。ありがとう、:) – Ryan

関連する問題