我的目标是设置一个数据结构来存储我的应用程序的设置。
在PHP中,我只想写...
$settings = array(
"Fullscreen" => true,
"Width" => 1680,
"Height" => 1050,
"Title" => "My Application",
);
现在我尝试在C ++中创建一个类似的结构,但它还不能处理不同的数据类型。顺便说一句,如果有更好的方式存储这些设置数据,请告诉我。
struct Setting{ string Key, Value; };
Setting Settings[] = {
("Fullscreen", "true"), // it's acceptable to store the boolean as string
("Width", "1680"), // it's not for integers as I want to use them later
("Height", 1050), // would be nice but of course an error
("Title", "My Application") // strings aren't the problem with this implementation
};
如何使用associative array
建模flexible datatypes
的结构?
答案 0 :(得分:8)
具有不同数据类型的关联数据结构正是struct
...
struct SettingsType
{
bool Fullscreen;
int Width;
int Height;
std::string Title;
} Settings = { true, 1680, 1050, "My Application" };
现在,也许您想要某种反射,因为字段名称将出现在配置文件中?类似的东西:
SettingsSerializer x[] = { { "Fullscreen", &SettingsType::Fullscreen },
{ "Width", &SettingsType::Width },
{ "Height", &SettingsType::Height },
{ "Title", &Settings::Title } };
只要你给SettingsSerializer
一个具有不同行为的重载构造函数,取决于指向成员的指针类型,就能找到你。
答案 1 :(得分:3)
C ++是一种强类型语言。容器只包含一种类型的对象,因此默认情况下,您只能使用标准C ++来完成所需的操作。
另一方面,您可以使用boost :: variant或boost :: any等库来提供可以容纳多种(或任何)类型之一的类型,然后在应用程序中使用该类型的容器。 / p>
您可以使用std::map
从设置名称映射到值,而不是数组:
std::map<std::string, boost::variant<bool,int,std::string> >
答案 2 :(得分:2)
#include <map>
#include <string>
std::map<std::string,std::string> settings;
settings.insert("Fullscreen","true");
settings.insert("Width","1680");
settings.insert("Height","1050");
settings.insert("Title","My Application");
如果你想坚持使用STL,可能是这样做的一种方式。
答案 3 :(得分:2)
一种解决方案可能是定义ISetting接口,如:
class ISetting{
public:
virtual void save( IStream* stream ) = 0;
virtual ~ISetting(){}
};
之后,您可以使用地图来存储您的设置:
std::map< std::string, ISetting* > settings;
布尔设置的一个示例是:
class BooleanSetting : public ISetting{
private:
bool m_value;
public:
BooleanSetting(bool value){
m_value = value
}
void save( IStream* stream ) {
(*stream) << m_value;
}
virtual ~BooleanSetting(){}
};
最后:
settings["booleansetting"]=new BooleanSetting(true);
settings["someothersetting"]=new SomeOtherSetting("something");
答案 4 :(得分:1)
一种可能的解决方案是创建一个类似于
的Settings
类
class Settings {
public:
Settings(std::string filename);
bool getFullscreen() { return Fullscreen; }
// ...etc.
private:
bool Fullscreen;
int Width;
int Height;
std::string Title;
};
这假定设置存储在某个文件中。可以使用构造函数来使用您选择的任何格式读取设置。当然,这样做的缺点是你必须修改类来添加任何其他设置。
答案 5 :(得分:0)
要回答您的问题,您可以使用boost::any
或boost::variant
来实现您的目标。我认为变体开始时更好。
boost::variant<
std::string,
int,
bool
> SettingVariant;
std::map<std::string, SettingVariant> settings;
为了不回答您的问题,使用无类型容器不是我所建议的。强类型为您提供了一种构造代码的方法,使编译器在您做错误的时候会给您带来错误。
struct ResolutionSettings {
bool full_screen;
size_t width;
size_t height;
std::string title;
};
然后只是一个简单的自由函数来获取默认设置。
ResolutionSettings GetDefaultResolutionSettings() {
ResolutionSettings settings;
settings.full_screen = true;
settings.width = 800;
settings.height = 600;
settings.title = "My Application';
return settings;
}
如果您正在从磁盘上读取设置,那么这是一个稍微不同的问题。我仍然会编写强类型设置结构,并让你的弱类型文件阅读器使用boost::lexical
强制转换来验证字符串转换是否有效。
ResolutionSettings settings;
std::string str = "800";
size_t settings.width = boost::lexical_cast<size_t>(str);
您可以将所有磁盘读取逻辑包装在另一个未与任何其他功能结合的功能中。
ResolutionSettings GetResolutionSettingsFromDisk();
我认为这是最直接和最容易维护的(特别是如果你在C ++中不是很舒服)。