我在配置类中要实现的某些功能有问题,我有一些不同类型的值,我想将它们存储在地图中。以前我使用ExtendedString类来存储所有数据,并在需要时使用模板函数将它们转换为所需类型。然后在我的配置类中有一个map<ExtendedString,vector<ExtendedString> >
来存储配置文件中的所有密钥。这是我的ExtendedString类已经是这样的:
class ExtendedString : public std::string
{
public:
ExtenedString() : public std::string
{
}
template <class T> ExtenededString(T)
{
std::stringstream s;
*this = s.str();
}
template <class T>T as(){
istringstream s(*this);
T temp;
d >> temp;
return temp;
}
}
现在我想在加载配置文件时解析所有值,并且还具有在需要时转换为任何可能类型的功能。例如,如果我将一些值解析为int并且在我的运行时我需要该值作为字符串我希望能够立即强制转换,除此之外我不想在这种情况下使用boost,它是我的基类之一我不想将提升链接到我正在开发的每个项目。
答案 0 :(得分:2)
一个经典解决方案是boost::any
,或大量union
。但我认为这两种方法都比他们解决的问题更麻烦。创建一个具有每个配置选项成员的Config
类有什么问题?
答案 1 :(得分:1)
您可以编写“Value”类,然后为每种值编写子类,而不是将它们全部存储为字符串。
答案 2 :(得分:1)
我建议使用boost::any
,因为它听起来像你正在寻找的。但是,如果你真的不想使用它,你可能能够像这样处理它。它可能不是最好的方法(这是我头脑中的第一件事) - 基本上它将值存储在你原来的类型和字符串中。如果您尝试将get
作为原始类型,则返回该值,否则,它将使用std::stringstream
尝试转换它。
注意:这不处理复制/分配,将d_data
更改为您选择的共享指针来处理它。
#include <string>
#include <sstream>
#include <iostream>
class ConfigValue
{
class HolderBase
{
protected:
virtual void writeValueToStream(std::ostream& os) const = 0;
public:
virtual ~HolderBase() { }
template <class Type>
Type getAs() const
{
std::stringstream ss;
writeValueToStream(ss);
Type temp;
ss >> temp;
return temp;
}
};
template <class Type>
class Holder : public HolderBase
{
Type d_value;
protected:
void writeValueToStream(std::ostream& os) const
{
os << d_value;
}
public:
Holder(const Type& value)
: d_value(value)
{
std::ostringstream oss;
oss << value;
}
Type get() const
{
return d_value;
}
};
HolderBase *d_data;
public:
template <class Type>
ConfigValue(const Type& value)
: d_data(new Holder<Type>(value))
{
}
~ConfigValue()
{
delete d_data;
}
template <class Type>
Type get() const
{
if (Holder<Type> *holder = dynamic_cast<Holder<Type>*>(d_data))
{
return holder->get();
}
else
{
return d_data->getAs<Type>();
}
}
};
int main()
{
ConfigValue cv = 10;
std::cout << cv.get<std::string>() << std::endl;
return 0;
}