2012-01-05 11 views
2

私はテンプレート化されたクラスのパラメータを持っています。 すべてのパラメータをコンテナに入れたいと思います。 私のパラメータが異なるタイプでインスタンス化されている場合、これを行う方法は?クラスContainerで C++では、異なるタイプのパラメータを持つ特殊なテンプレートオブジェクトのコンテナを使用できますか?

は、私が は可能ではないように思われるさまざまなタイプ(int型、ダブル、...)または同等のものからベクトル<パラメータ* >を持っていると思います。

パラメータクラスが基本クラスから派生している場合、コンテナはvectをベクトル< Base * >として宣言できます。しかし、この場合は、Container :: fooに特有なことは何もできません。

以下は私のソースの例です。私のパラメータの1つはostreamと互換性のないQStringです。

ご意見ありがとうございます。



    #include <QString> 
    #include <vector> 
    #include <iostream> 
    #include <string> 
    #include <sstream> 
    using namespace std; 

    #define P(a) cout << #a << ":" << a << endl 

    /* 
    class Base { 

    }; 
    */ 

    template<typename T> class Parameter /*: public Base */ { 
    private: 
     T val; 
    public: 
     void setVal(const T &val) { 
      this->val = val; 
     } 
     const T &getVal() { 
      return val; 
     } 
     string getFoo() { 
      stringstream s; 
      s << val; 
      return s.str(); 
     } 
    }; 

    template<> 
    string Parameter<QString>::getFoo() { 
     stringstream s; 
     s << val.toStdString(); 
     return s.str(); 
    } 

    class Container { 
    public: 
     void push_back(Parameter *base) { 
      vect.push_back(base); 
     } 
     void foo() { 
      /* do something with the parameters */ 
     } 
    private: 
     vector<Parameter*> vect; 
    }; 

    int main() { 
     Parameter<int> pi; 
     Parameter<QString> ps; 

     pi.setVal(10); 
     ps.setVal("QString"); 

     P(pi.getVal()); 
     P(ps.getVal().toStdString()); 

     P(pi.getFoo()); 
     P(ps.getFoo()); 

     Container container; 
     container.push_back(&pi); 
     container.push_back(&ps); 
    } 

コメントいただきありがとうございます。私はあなたの助言に従い、boost :: anyを使用します。



    #include <boost/any.hpp> 
    #include <QString> 
    #include <vector> 
    #include <iostream> 
    #include <string> 
    #include <sstream> 
    using namespace std; 

    #define P(a) cout << #a << ":" << a << endl 

    template<typename T> class Parameter { 
    private: 
     T val; 
    public: 
     void setVal(const T &val) { 
      this->val = val; 
     } 
     const T &getVal() { 
      return val; 
     } 
     string getFoo() { 
      stringstream s; 
      s << val; 
      return s.str(); 
     } 
    }; 

    template<> 
    string Parameter<QString>::getFoo() { 
     stringstream s; 
     s << val.toStdString(); 
     return s.str(); 
    } 

    class Container { 
    public: 
     void push_back(boost::any base) { 
      vect.push_back(base); 
     } 
     void foo() { 
      cout << "do something with the parameters\n"; 
      for (vector<boost::any>::iterator i = vect.begin(); i != vect.end(); ++i) { 
       boost::any a = (*i); 
       if (a.type() == typeid(Parameter<int>*)) { 
        Parameter<int> *ai = boost::any_cast<Parameter<int> *>(a); 
        cout << ai->getFoo() << endl; 
       } else if (a.type() == typeid(Parameter<QString>*)) { 
        Parameter<QString> *aq = boost::any_cast<Parameter<QString> *>(a); 
        cout << aq->getFoo() << endl; 
       } else { 
        cout << "unknown type:" << a.type().name() << endl; 
       } 
      } 
     } 
    private: 
     vector<boost::any> vect; 
    }; 

    int main() { 
     Parameter<int> pi; 
     Parameter<QString> ps; 

     pi.setVal(10); 
     ps.setVal("QString"); 

     P(pi.getVal()); 
     P(ps.getVal().toStdString()); 

     P(pi.getFoo()); 
     P(ps.getFoo()); 

     Container container; 
     container.push_back(&pi); 
     container.push_back(&ps); 
     container.foo(); 
    } 



+0

Qstringは "ostreamと互換性がありません"とはどういう意味ですか?この問題はどのように関連していますか?パラメータ :: getFoo()を呼び出そうとしていますか?意味のある場合には、演算子をQstringで動作させるためのメソッドを提供することができます。 – bacar

+0

まさにあなたは何をしようとしていますか?ベースを使って問題を解決できないのはどうですか?タイプに固有のいくつかの機能(「Container :: fooで特定のことは何もできません」)を持っている間に、複数のタイプに共通するものがほしいと思うように思えます。 – bacar

+0

@bacarテンプレートクラスのgetFoo()はQStringでは機能しません。 ■< < val.toStdString()を使用する必要があります。
user1132852

答えて

2

あなたはあらゆる種類のデータを保持することができますBoost.Anyを使用することができます。ここでは が更新されたバージョンです。次に、boost::any_cast<>を使用して、オブジェクトを正しいタイプに戻します。

それ以外の場合は、基本クラスのアプローチに進む必要がありますが、先に述べたように、Container::fooは何か便利なことをするのは難しいかもしれません。

この問題を解決する方法の1つは、すべてのfoo関数をパラメータとして文字列を取得することです。次に、関数の特定の実装はその文字列を解析し、正しい型に変換します。

編集: Boost.Anyの例は:

#include <iostream> 
#include <boost/any.hpp> 

int main() 
{ 
    boost::any param = 89; 

    // This will fail because `param` is currently holding an int 
    // not a char 
    char ch = boost::any_cast<char>(param); 

    // This works 
    int i = boost::any_cast<int>(param); 

    // You can always change the value and type of what 
    // `param` is holding 
    param = "example"; 
} 
+0

あなたの最後のコメントはOKですが、質問は残っています:どのようにタイプするの?あなたはBoost.Anyを使っていますか? – user1132852

+0

@ user1132852 Boost.Anyの使い方の最小限の例を投稿しました。 –

+0

Boost.Anyは過剰殺人のようです。 OPは、_any_タイプではなく、関連するタイプを含んでいます。ベクトルは、コンテナをParameterオブジェクトに制限することはできません。あなたはブーストから何の利点を得ますか?単純なdynamic_castから手に入れないのはここですか? – bacar

0

コンテナ内のすべてのものは、同じタイプである必要があります。私はあなたのアプローチに似た何かを行いました。そこでは、いくつかの有用なジェネリックインターフェイスを持ち、派生したクラスがテンプレート化された基本クラスを作成しました。ソリューションにアプローチする他の唯一の方法は、型を示す値を返す基本クラス関数を定義し、次に基底を降下させることです。

2

正しい解決策は、あなたがあなたがする必要があるすべてを行うことができますことができるように、基本クラスのために良い十分なインタフェースを記述することです:

class Base { 
public: 
    virtual void *GetVal() const=0; 
    virtual void SetVal(void *ptr)=0; 
    virtual std::string Type() const=0; 
    virtual std::string GetAsString() const=0; 
}; 

これはあなたが望むものではないかもしれませんが、それはまだから値を渡すことができます1つのパラメータを次のパラメータに渡します。実際の値を求めたら、コンパイル時に型を知る必要があります。このタイプのスイッチケースは、ランタイムを作成する際に役立ちます。

+1

このような 'void *'を使うと、エラーが起こりやすくなります。私は間違いなく 'boost :: any'に変更します。 –

+0

はい、ContainerクラスのSwitch-caseにするには、すべてのケースを知る必要があります。> – user1132852

+0

any_castを使用するよりもエラーが発生しなくなりました。ダウンキャスト操作は常に危険になりますが、void *は危険なものがここで発生していることを記録しています。 – tp1

関連する問題