2016-08-31 16 views
-4

マップに複数のタイプのオブジェクトを格納したいと思い、この解決策を思いつきました。私は各オブジェクトの型を知っていなければならないので、boost :: anyを使うことはできません。これを行うにはより良い方法がありますか、これは容認できる解決策ですか?マップに複数のタイプを格納する

enum eType 
{ 
    TYPE_STRING, 
    TYPE_NUMBER, 
}; 

class CType 
{ 
public: 
    int GetType() { return m_Type; } 

protected: 
    int m_Type; 
}; 

template <typename T> 
class CData : public CType 
{ 
public: 
    CData(const T & rData, int iType) 
    { 
     m_Type = iType; 
     m_Data = rData; 
    } 

    T & GetData() { return m_Data; } 

private: 
    T m_Data; 
}; 

std::map<unsigned long, CType *> map_Data; 

void main() 
{ 
    // Create a new data with TYPE_NUMBER 
    CData<short> data(32767, TYPE_NUMBER); 

    // Add it to the map 
    map_Data[0] = &data; 

    // Get the type 
    switch (map_Data[0]->GetType()) 
    { 
     case TYPE_NUMBER: 
     { 
      // Cast the first element to CData 
      CData<short> * pField = (CData<short> *)map_Data[0]; 

      // Print the data 
      printf("Data: %d\n", pField->GetData()); 
     } 
     break; 

     case TYPE_STRING: 
     { 
      // Cast the first element to CData 
      CData<std::string> * pField = (CData<std::string> *)map_Data[0]; 

      // Print the data 
      printf("Data: %s\n", pField->GetData().c_str()); 
     } 
     break; 
    } 
} 
+1

実行しようとしましたか?また 'void main'は存在しません – TemplateRex

+0

確かに私は試みました、それはVisual Studioで動作します。 – JOkle

+0

あなたは意見を求めています。あなたがそれを実行した場合、コンパイラはそれを受け入れました。それで十分ですか? – CAB

答えて

1

boost::anyおよびboost::any_castを使用してください。

anyがintかどうかを確認します。あなたが解決策を使用するために、getTypeのような機能を持つ基本的かつ簡単に、あなたのクラスを汚染したくない場合は任意のタグ付きを使用しているconst char *

bool is_char_ptr(const boost::any & operand) 
{ 
    try 
    { 
     any_cast<const char *>(operand); 
     return true; 
    } 
    catch(const boost::bad_any_cast &) 
    { 
     return false; 
    } 
} 
0

であるかどうかを確認するために

bool is_int(const boost::any & operand) 
{ 
    return operand.type() == typeid(int); 
} 

チェック次の例のような組合:

#include <map> 

struct StructA { }; 
struct StructB { }; 

struct TaggedUnion { 
    enum { A, B } tag; 
    union { 
     StructA a; 
     StructB b; 
    }; 
}; 

int main() { 
    std::map<std::size_t, TaggedUnion> map; 
    map[0] = TaggedUnion{ TaggedUnion::A, StructA{} }; 

    switch(map[0].tag) { 
    case TaggedUnion::A: 
     // do whatever you want with map[0].a; 
     // ... 
     break; 
    case TaggedUnion::B: 
     // do whatever you want with map[0].b 
     // ... 
     break; 
    } 
} 
0

あなたの質問は面白いですし、私はなぜそんなにdownvoted理解していません。残念ながら、あなたがやろうとしていることはC++では不可能です(JavaまたはC#で実行可能かどうか疑問です)

私はあなたの質問の中核であると思うリンクを再度入れます。この実装のうち

creating-an-interface-for-an-abstract-class-template-in-c++

は面白いです。

#include <iostream> 
#include <string> 
#include <sstream> 
#include <List> 

using namespace std; 

struct CType 
{ 
    int GetType() { return m_Type; } 
    string GetStringVal() { return m_string_val; } 
    enum eType {  TYPE_STRING, 
        TYPE_NUMBER }; 
protected: 
    int m_Type; 
    string m_string_val; 
}; 

template <typename T> 
class CData : public CType 
{ 
public: 
    CData(const T & rData):m_Data(rData) 
    { 
     stringstream strs; 
     m_Type = GetType(); 
     //Mingw bug 
     //m_string_val = std::to_string(m_Data); //c++11 
     strs << m_Data; 
     m_string_val = strs.str(); 
    } 

    T & GetData() { return m_Data; } 

private: 
    T m_Data; 
    CType::eType GetType(); 
}; 

template<> CType::eType CData<int>::GetType() { return TYPE_NUMBER; }; 
template<> CType::eType CData<string>::GetType() { return TYPE_STRING; }; 
//More specialization here 

int main() 
{ 
    cout << "Hello world!" << endl; 

    CData<int> cd_int(5); 
    CData<string> cd_str("SO contribution"); 

    list<CType> my_list = { cd_int, cd_str }; 

    for (auto & elem : my_list) 
     cout << elem.GetStringVal() << endl; 

    return 0; 
} 

結果は当然です:

こんにちは、私はあなたが厄介なスイッチケースなしでいくつかの行を惜しまことができると思うように私はちょうどここにいくつかの手直しを入れて!

SO寄与

----- アドオン 2016 9月 - 05 -----

別の可能性は、機能を記憶することである( "とラムダこの「捕捉」)は結果自体の代わりに結果を返します。 m_Dataフィールドが変更されたときに更新を実行しないようにします。

#include <iostream> 
#include <string> 
#include <sstream> 
#include <List> 
#include <functional> 

using namespace std; 

struct CType 
{ 
    int GetType() { return m_Type; } 
    string GetStringVal() { return m_string_func(); } 
    enum eType {  TYPE_STRING, 
        TYPE_NUMBER }; 
protected: 
    int m_Type; 
    function<string()> m_string_func ; 
}; 

template <typename T> 
class CData : public CType 
{ 
    public: 
    CData(const T & rData):m_Data(rData) 
    { 
     m_Type = GetType(); 
     m_string_func = [this](){ //MinGW bug,otherwise to_string() 
            stringstream strs; 
            strs << m_Data; 
            return strs.str();}; 
    } 

private: 
    T m_Data; 
    CType::eType GetType(); 
}; 

template<> CType::eType CData<int>::GetType() { return TYPE_NUMBER; }; 
template<> CType::eType CData<string>::GetType() { return TYPE_STRING; }; 

int main() 
{ 
    cout << "Hello world!" << endl; 

    CData<int> cd_int(5); 
    CData<string> cd_str("SO contribution"); 

    list<CType> my_list = { cd_int, cd_str }; 

    for (auto & elem : my_list) 
     cout << elem.GetStringVal() << endl; 

    return 0; 
} 
関連する問題