2012-11-19 5 views
15

注:私は、これはSOの前に頼まれているに類似の質問を知っているが、私は彼らが役に立つか、非常に明確で見つけることができませんでした。Cはベクトル上に複数のタイプをプッシュ++

第2のメモ:このプロジェクト/割り当ての範囲については、私はBoostのようなサードパーティのライブラリを避けようとしています。

私はそのインデックスのそれぞれに、複数のタイプを保持する単一のベクターを持つことができる方法があるかどうかを確認しようとしています。例えば、私は次のコードサンプルを持っていると言う:

vector<something magical to hold various types> vec; 
int x = 3; 
string hi = "Hello World"; 
MyStruct s = {3, "Hi", 4.01}; 

vec.push_back(x); 
vec.push_back(hi); 
vec.push_back(s); 

私はvector<void*>は仕事ができると聞きましたが、その後、それはメモリの割り当てとトリッキー取得し、近くのメモリ内の特定の部分が意図せずになる可能性が常にあります特定のインデックスに挿入された値が予想よりも大きい場合はオーバーライドされます。

の可能性がありますタイプはベクターに挿入できますが、これらのタイプはすべて同じスーパークラスから派生しているわけではなく、これらのタイプがすべてプッシュされる保証はありませんベクトルまたはどのような順序。

安全に私のコードサンプルで実証した目的を達成する方法はありますか?

ありがとうございます。

+0

が、私は明確ではありませんでした申し訳ありません@クリス:私たちがやりたいすべてがコンソールにオブジェクトを印刷であれば

は、ここでの例です。このプロジェクト/割り当ての範囲については、私は第三者図書館を避けようとしています。私は私の質問を更新しました。 –

+0

さて、どのようにうまくいくのか分かりませんが、 'type'メンバとすべての可能な型の和集合を持つ構造体を持つことができます。 – chris

+3

実際にプッシュされていることを*知ることができないことを義務づけているのであれば、このベクトルはポインタ以外に何も所有していないと仮定できますか?所有者レベルでタイプ情報を確立する何らかの方法がなければ、クリーンアップまたは消去を適切に管理することにいくらか悩まされます。ポインタ+デストラクタ参照を持つ構造体が考えられますが、実際のデータモデルはここで処理されているのですか? – WhozCraig

答えて

6

:非常にラフと不完全なアウトラインは次のようになります。

以前にType-Bを格納していたときにType-Aを取得しようとすると、このクラスに例外がスローされることもあります。

は、ここに私のプロジェクトの一つからHolderクラスの一部です。おそらくここから始めることができます。

注:による無制限組合の使用に、C++ 11でのみ動作。これについて詳しい情報はここで見つけることができます:What are Unrestricted Unions proposed in C++11?

class Holder { 
public: 
    enum Type { 
     BOOL, 
     INT, 
     STRING, 
     // Other types you want to store into vector. 
    }; 

    template<typename T> 
    Holder (Type type, T val); 

    ~Holder() { 
     // You want to properly destroy 
     // union members below that have non-trivial constructors 
    } 

    operator bool() const { 
     if (type_ != BOOL) { 
      throw SomeException(); 
     } 
     return impl_.bool_; 
    } 
    // Do the same for other operators 
    // Or maybe use templates? 

private: 
    union Impl { 
     bool bool_; 
     int int_; 
     string string_; 

     Impl() { new(&string_) string; } 
    } impl_; 

    Type type_; 

    // Other stuff. 
}; 
+0

'9.5/1'のために' std :: string'をunionに入れられないことは間違いありませんが、それは単純なコンストラクタ、コピーコンストラクタ、デストラクタ、またはコピー代入演算子。 –

+2

あなたは今、C++ 11ですべての利点があります:p [wikipedia](http://en.wikipedia.org/wiki/C%2B%2B11#Unrestricted_unions)で参照できます。 –

+2

これはあなたの答えの中でC++ 11のみの解決策であり、 'string'メンバを安全に使うために配置の新しく明示的な破壊を使わなければならないことに注意してください。 –

16

オブジェクトは、均質型であるstd::vector<T>必要により保持します。異なるタイプのオブジェクトを1つのベクトルに配置する必要がある場合は、何らかの形でそれらの型を消去し、それらをすべて同じようにする必要があります。あなたはboost::anyまたはboost::variant<...>という道徳上の同等物を使うことができます。 boost::anyのアイデアは、型の階層をカプセル化し、基底へのポインタを格納するが、テンプレート化された派生型を指すことです。あなたは間違いなく何とかベクトルから、あなたのオブジェクトの型情報を隠すためにラッパークラスが必要になります、それを行うためには

#include <algorithm> 
#include <iostream> 

class any 
{ 
private: 
    struct base { 
     virtual ~base() {} 
     virtual base* clone() const = 0; 
    }; 
    template <typename T> 
    struct data: base { 
     data(T const& value): value_(value) {} 
     base* clone() const { return new data<T>(*this); } 
     T value_; 
    }; 
    base* ptr_; 
public: 
    template <typename T> any(T const& value): ptr_(new data<T>(value)) {} 
    any(any const& other): ptr_(other.ptr_->clone()) {} 
    any& operator= (any const& other) { 
     any(other).swap(*this); 
     return *this; 
    } 
    ~any() { delete this->ptr_; } 
    void swap(any& other) { std::swap(this->ptr_, other.ptr_); } 

    template <typename T> 
    T& get() { 
     return dynamic_cast<data<T>&>(*this->ptr_).value_; 
    } 
}; 

int main() 
{ 
    any a0(17); 
    any a1(3.14); 
    try { a0.get<double>(); } catch (...) {} 
    a0 = a1; 
    std::cout << a0.get<double>() << "\n"; 
} 
+0

+1、良い答えですが、データを覚えていますが、 ' * cloneそれは共変です:)しかし、これは間違いなく受け入れられた答えより良い答えです。 –

4

としては、あなたがなど労働組合の様々な形、変異体、あなたが保存されたオブジェクトで何をしたいのかに応じて、外部の多型が正確に何を行う可能性を使用することができます示唆しましたあなたは、基本クラスのインタフェース内のすべての必要な操作を定義することができる場合は、をしたいです。

#include <iostream> 
#include <string> 
#include <vector> 
#include <memory> 

class any_type 
{ 
public: 
    virtual ~any_type() {} 
    virtual void print() = 0; 
}; 

template <class T> 
class concrete_type : public any_type 
{ 
public: 
    concrete_type(const T& value) : value_(value) 
    {} 

    virtual void print() 
    { 
     std::cout << value_ << '\n'; 
    } 
private: 
    T value_; 
}; 

int main() 
{ 
    std::vector<std::unique_ptr<any_type>> v(2); 

    v[0].reset(new concrete_type<int>(99)); 
    v[1].reset(new concrete_type<std::string>("Bottles of Beer")); 

    for(size_t x = 0; x < 2; ++x) 
    { 
     v[x]->print(); 
    } 

    return 0; 
} 
+1

'' print() 'ではなく' 'T get()' '関数を使うことができますか?v [x] :: T result = v [x] .get()'? –

+0

「基本クラスのインタフェースで必要なすべての操作を定義できるかどうか」の説明の部分を強調することをお勧めします。これはソリューションが動作しない場合は不可欠です。メンバー変数にも同じことが当てはまります。 – chutsu

関連する問題