タイプ不定、要素数不定のデータを扱うオブジェクトをvectorで管理するには


ある種のデータの型もサイズも不定なシリアルなデータをオブジェクトで管理してそのオブジェクトを複数作ってvectorで管理したいとする。

データ型もサイズも不定な為にオブジェクトはテンプレートを利用する。

```
template<typename T>
class DataHolder{
    const vector<T> data;
public:
    DataHolder(const vector<T> &data):data(data){}
};
```
でこれのインスタンスをいっぱい作って、vectorで管理しようとしても、テンプレートなのでうまくいかない。

```
int main(int argc, const char * argv[]) {
    vector<DataHolder<double>> dataVector;
    DataHolder<double> d1({1.3, 2.4, 3.3});
    DataHolder<string> d2({"hello", "bye"});
    dataVector.push_back(d1);
    // dataVector.push_back(d2);
    return 0;
}
```
当然doubleとstringで２つのクラスをテンプレートは作るわけで、それを一つvectorに入れるのは不可能。どうしても入れたい場合は、動的にクラスをインスタンス化してスーパークラスへのポインタをvectorにいれるしかない。
で、生ポインタは当然使いたくないのでshared_ptrかunique_ptrだが、shared_ptrを入れる。

```
#include <iostream>
#include <vector>
#include <memory>

using namespace std;

class _DataHolder{
};

template<typename T>
class DataHolder : public _DataHolder{
    const vector<T> data;
public:
    DataHolder(const vector<T> &data):data(data){}
    const vector<T> &getData() const{return data;};
};

int main(int argc, const char * argv[]) {
    vector< shared_ptr<_DataHolder>> dataVector;
    dataVector.push_back(shared_ptr<_DataHolder>(new DataHolder<double>({1.3, 2.4, 3.3})));
    dataVector.push_back(shared_ptr<_DataHolder>(new DataHolder<string>({"hello", "bye"})));
    
    auto d1 = static_cast<DataHolder<double>*>(dataVector[0].get())->getData();
    auto d2 = static_cast<DataHolder<string>*>(dataVector[1].get())->getData();

    cout << d1[0] << " " << d1[1] << " " << d1[2] << endl;
    cout << d2[0] << " " << d2[1] << endl;

    return 0;
}
```
これで一応、不定データを持つ複数のオブジェクトをvectorで管理できるようになるが...。

受け取る時に当然キャストを間違う可能性がある。
たとえば

```


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

using namespace std;

class _DataHolder{
};

template<typename T>
class DataHolder : public _DataHolder{
    const vector<T> data;
public:
    DataHolder(const vector<T> &data):data(data){}
    const vector<T> &getData() const{return data;};
};

int main(int argc, const char * argv[]) {
    vector< shared_ptr<_DataHolder>> dataVector;
    dataVector.push_back(shared_ptr<_DataHolder>(new DataHolder<double>({1.3, 2.4, 3.3})));
    dataVector.push_back(shared_ptr<_DataHolder>(new DataHolder<string>({"hello", "bye"})));
    
    auto d1 = static_cast<DataHolder<string>*>(dataVector[0].get())->getData();
    auto d2 = static_cast<DataHolder<double>*>(dataVector[1].get())->getData();

    cout << d1[0] << " " << d1[1] << " " << d1[2] << endl;
    cout << d2[0] << " " << d2[1] << endl;

    return 0;
}
```
だとランタイムエラー食らうから、なんらかの手を考えなければいけない。
でもどうやって？

typeidとかどこかで使うとかかなぁ。

以下、コメントにしたがってdynamic_castを使って、型を間違った場合にランタイムエラーにならないようにしてみました。

```
using namespace std;

class _DataHolder{
    virtual void dummy(){};
};

template<typename T>
class DataHolder : public _DataHolder{
    const vector<T> data;
public:
    DataHolder(const vector<T> &data):data(data){}
    const vector<T> &getData() const{return data;};
    virtual void dummy(){}
};

int main(int argc, const char * argv[]) {
    vector< shared_ptr<_DataHolder>> dataVector;
    dataVector.push_back(shared_ptr<_DataHolder>(new DataHolder<double>({1.3, 2.4, 3.3})));
    dataVector.push_back(shared_ptr<_DataHolder>(new DataHolder<string>({"hello", "bye"})));
    
    auto dh1 = dynamic_cast<DataHolder<string>*>(dataVector[0].get());
    if (dh1 != nullptr) {
        auto d1 = dh1->getData();
        cout << d1[0] << " " << d1[1] << " " << d1[2] << endl;
    }
    auto dh2 = dynamic_cast<DataHolder<double>*>(dataVector[1].get());
    if (dh2 != nullptr){
        auto d2 = dh1->getData();
        cout << d2[0] << " " << d2[1] << endl;
    }
    return 0;
}
```

kktk-KOさんのコメントにしたがってboost::anyで書いてみました。
C++とは思えない感じになってきましたが、当然ながらboost::any_castで戻す時に間違った型を指定するとランタイムエラーになります。なので、typeidを使ってチェックを入れています。

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

using namespace std;

int main() {
    vector< boost::any > dataVector;

    dataVector.push_back(vector<double>({1.3, 2.4, 3.3}));
    dataVector.push_back(vector<string>({string("hello"), string("bye")}));
    
    auto dh1 = dataVector[0];
    
    if (dh1.type() == typeid(vector<double>)){
        auto d1 = boost::any_cast<vector<double>>(dh1);
        for (double d : d1){
            cout << d << " ";
        }
        cout << endl;
    }
    auto dh2 = dataVector[1];
    if (dh2.type() == typeid(vector<string>)){
        auto d2 = boost::any_cast<vector<string>>(dh2);
        for (string d : d2){
            cout << d << " ";
        }
        cout << endl;
    }
    return 0;
}
```