我想在地图中存储多种类型的对象,我想出了这个解决方案。我必须知道每个对象的类型,所以我不能使用 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;
}
}
答案 0 :(得分:1)
检查any是否为int;
bool is_int(const boost::any & operand)
{
return operand.type() == typeid(int);
}
检查any是否为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;
}
}
答案 1 :(得分:0)
如果您不想使用getType
等函数污染您的类,一个基本且易于使用的解决方案是使用标记联合,如下例所示:
#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;
}
}
答案 2 :(得分:0)
你的问题很有趣,我不明白为什么这么沮丧。不幸的是,你想要做的事情在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;
}
结果很自然:
Hello world!
5
SO贡献
----- ADD-ON 2016-Sept-05 -----
另一种可能性是存储一个函数(带有“this”捕获的lambda)返回结果而不是结果本身。它避免在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;
}