2016-12-04 11 views
1

免責事項:私の質問に対する短い答えは "できません"と思っています。しかし、私はC++の専門家ではないので、私はまだ試してみて、ここで尋ねると思っていました。私が気づいていない解決策があるかもしれません。C++でテンプレート化されていないクラスでテンプレート化されたクラスを "ラップ"できますか?

私はがクラステンプレートタイプであるstd::list<T>に内部的にデータを格納するテンプレート化されたコンテナのようなクラスMyContainerを持っています。これは正常に動作します。

今度は別のクラスを追加したいと思います。このクラスは、そのテンプレートコンテナクラスのインスタンスをstd::map<std::string, MyContainer>にマップする必要があります。しかし、コンパイラは、std::map<std::string, MyContainer<T>>のように、マップの値部分のテンプレートクラスタイプを指定するように求めます。しかし、ここではこのテンプレートを省略することになります。これは、ラッパークラスのテンプレートも使用する必要があるためです。

私の質問:少なくともいくつかの拡張には、ラッパークラスのテンプレートの種類を省略して、私がやろうとしていることを達成するための方法はありますか?あるいは、これはC++では不可能です。なぜなら、コンパイラはその情報を必要とするからです。

+8

「テンプレートクラス」のようなものはありません。 C++にはクラステンプレートがあります。クラステンプレートはクラスではありません。あなたの説明ははっきりしていません。コードをもっと表示してください。 –

答えて

3

これを行う一般的な手法の1つは継承です。

MyContainer<T>は、MyBaseContainerなどの基本クラスから継承します。 MyBaseContainerはテンプレートクラスではなく、MyContainerです。 MyBaseContainerクラスには、テンプレート化されたクラスがオーバーライドする仮想関数があります。

次に、タイプstd::map<std::string, MyBaseContainer*>のマップを作成します。それぞれのテンプレートタイプを知らなくても、格納されているコンテナの仮想関数を呼び出すことができます。

これはstd::functionの動作方法です。

+0

ああ、意味があります。ありがとう! – Matthias

+1

ここで唯一の問題は、MyBaseContainerがあまりにも多くの有用な仮想関数を持つことができないことです。 –

+0

絶対に必要な場合は、 'MyBaseContainer'ポインタに' dynamic_cast *>() '(あるいは場合によっては' static_cast')を使用することもできます。しかし、それはかなり醜いデザインです。 – microtherion

1

これは可能ですが、少し複雑です。私があなたを正しく理解している場合、map内に格納されている各MyContainerクラスは、異なるテンプレートの特殊化を持っている可能性があります(を保持するものとstd::list<string>を保持するものがあります)。その場合、マップの値の型はもうMyContainerlist<int>およびlist<string>

@IanPudneyが既に指摘しているように継承を使用する1つの方法です。

あなたもmap<string, boost::any>http://www.boost.org/doc/libs/1_61_0/doc/html/boost/any.htmlを参照)として、あなたが代わりにあなたが継承階層を作成する必要なしに、このマップ内MyContainerのいずれかの種類を格納することができるようになりますそのようにマップを宣言した場合MyContainerのクラスの継承階層を作成せずにこれを行うことができますしかし、あらかじめ。

+0

このアイデアをお寄せいただきありがとうございます。私はむしろブーストlib(または他のサードパーティ製のlib)を使用しないでください。 – Matthias

0

継承を使用せずにこれを行う方法は2つありますが、これはいくつかの決定要因にも左右されます。最初の質問は:外部クラスのインスタンスを作成する際には、既知のテンプレートコンテナのタイプです。そうであれば、このクラスは簡単に書くことができます。そうでなければ、それでもやることができますが、もっと多くの作業が必要になります。大文字小文字が分からない場合は、これを行う2つの方法があります。最初は、これをクラステンプレートにしないことで回避しようとしているものです。 2番目の方法は、このクラスを定義する方法のいくつかの論理を示すより多くの作業を含んでいます。

擬似コード: - 第一ケースタイプは、タイプがラッパーをテンプレート化することなく、メソッドを使用して知られていない第二の場合について

#include <map> 

template<class T> 
class MyContainer { 
    // ... Class Variables, Constructors & Methods 
} 

// For Demonstration We will say that `T` is known to be an int upon instantiation 
class MyClass { 
private: 
    std::map< std::string, MyContainer<int> > maps_; 

public: 
    MyClass() {} 
    ~MyClass() { 
     // Clear Out Map 
    } 

    void addItem(std::string& str, int value) { 
     maps_.insert(std::make_pair(str, MyContainer<int>(value)); 
    }   
}; 

今作成時に知られている、あなたはを知っておく必要がありますこのクラスがサポートできるすべてのタイプがあり、これらのそれぞれのtypedefを作成する必要があります。

擬似コード - タイプが知られていない第二ケース:

#include <map> 

template<class T> 
class MyContainer { 
    // ... Class Variables, Constructors & Methods 
} 

// For Demonstration We will say that `T` is unknown before instantiation 
class MyClass { 
public: 
    typedef MyContainer<int> INTS; 
    typedef MyContainer<float> FLOATS; 
    typedef MyContainer<double> DOUBLES; 
    // And Do This For Every Type This Class Will Support. 

private: 
    std::map< std::string, INTS > mapInts_; 
    std::map< std::string, FLOATS > mapFloats_; 
    std::map< std::string, DOUBLES > mapDoubles_; 
    // And You Will Need A Container For Each Supporting Type 
public: 

    MyClass() {} 
    // If You Have Constructors Other Than Default That Excepts Parameter Types 
    // You Will Need A Constructor For Each Supporting Type 

    ~MyClass() { 
     // Clear Out All Maps 
    } 

    void addInts(std::string& str, MyClass::INTS); 
    void addFloats(std::string& str, MyClass::FLOATS); 
    void addDoubles(std::string& str, MyClass::DOUBLES); 
    // And You Will Need A Corresponding Function For Each Type This Class Supports. 

}; 
関連する問題