C++ 在C+中是否有一种优雅的方式来表示包含不同类型的映射+;?
我正在构建一个类,我想使用各种参数来配置它,这些参数可以是:C++ 在C+中是否有一种优雅的方式来表示包含不同类型的映射+;?,c++,types,C++,Types,我正在构建一个类,我想使用各种参数来配置它,这些参数可以是:int、double和string(或者const char*)。在Ruby这样的语言中,我将构建一个初始化函数,该函数接受一个字符串键控的哈希值。例如: class Example def init_with_params params puts params end end e = Example.new e.init_with_params({ "OutputFile" => "/tmp/out.txt",
int
、double
和string
(或者const char*
)。在Ruby这样的语言中,我将构建一个初始化函数,该函数接受一个字符串键控的哈希值。例如:
class Example
def init_with_params params
puts params
end
end
e = Example.new
e.init_with_params({ "OutputFile" => "/tmp/out.txt", "CaptureFPS" => 25.0, "RetryDelaySeconds" => 5 })
<>如何在C++中创建类似的行为?< /P>
环顾四周,我发现有几篇帖子在谈论boost::variant
。我宁愿避免使用boost,如果通过将不同的类型限制为我上面提到的3种类型,就可以得到一个相当干净的解决方案
编辑:
我同意使用设计良好且经过广泛测试的代码(如Boost.Variant)比重新实现相同的想法要好得多。在本例中,问题简化为仅使用3种基本类型,因此我正在寻找实现它的最简单方法 如果您想避免使用Boost,可以将Boost.Variant的代码复制粘贴到您的项目中。无论如何,这只是标题。或者你可以通过实现一个通常被称为“有区别的联合”来重新发明轮子。如果我理解得很好,你需要一个
std::map
(或者更好的是,一个std::unordered_map
,因为你需要哈希),其中a
是一个字符串,B
可以是int
,double
或std::string
对于
B
可以使用boost::any
。否则,如果你不想使用Boost,你可以使用一个歧视的<代码>联合<代码>。< /P> < P>最有意义的事情是使用Boo.Stand,它是由C++程序员开发的,并被数百个项目磨练和测试。
但如果这不是你的选择,我看到以下备选方案:
std::string
中,并在getter中转换它们(最初在@Galik的评论中建议)下面是我经常用来存储程序配置属性的精简版本,也许您会发现它很有用:
#include <map>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
#include <initializer_list>
class config
{
// everything is stored internally as std::strings
// usually read from a configuration file
typedef std::map<std::string, std::string> prop_map;
typedef prop_map::const_iterator prop_map_citer;
prop_map props;
public:
// example constructor. Normally I have a method to read the
// values in from a file
config(std::initializer_list<std::pair<std::string, std::string>> list)
{
for(const auto& p: list)
props[p.first] = p.second;
}
// values are converted as they are requested to whatever types
// they need to be. Also a default may be given in case the value
// was missing from the configuration file
template<typename T>
T get(const std::string& s, const T& dflt = T()) const
{
prop_map_citer found = props.find(s);
if(found == props.end())
return dflt;
T t;
std::istringstream(found->second) >> std::boolalpha >> t;
return t;
}
// std::strings need special handling (no conversion)
std::string get(const std::string& s, const std::string& dflt = "") const
{
prop_map_citer found = props.find(s);
return found != props.end() ? found->second : dflt;
}
};
int main()
{
const config cfg =
{
{"OutputFile", "/tmp/out.txt"}
, {"CaptureFPS", "25.0"}
, {"RetryDelaySeconds", "5"}
};
std::string s;
float f;
int i;
s = cfg.get("OutputFile");
f = cfg.get<float>("CaptureFPS");
i = cfg.get<int>("RetryDelaySeconds");
std::cout << "s: " << s << '\n';
std::cout << "f: " << f << '\n';
std::cout << "i: " << i << '\n';
}
#包括
#包括
#包括
#包括
#包括
#包括
类配置
{
//所有内容都以std::strings的形式存储在内部
//通常从配置文件读取
typedef std::map prop_map;
typedef属性映射::常量迭代器属性映射;
道具地图道具;
公众:
//示例构造函数。通常我有一个方法来读取
//文件中的值
配置(标准::初始值设定项\u列表)
{
用于(常数自动和p:列表)
道具[p.first]=p.second;
}
//值在被请求时转换为任何类型
//它们必须是。如果值为
//配置文件中缺少
模板
T get(const std::string&s,const T&dflt=T())const
{
prop\u map\u citer found=props.find(s);
if(found==props.end())
返回dflt;
T;
std::istringstream(发现->秒)>>std::boolalpha>>t;
返回t;
}
//std::字符串需要特殊处理(无转换)
std::string get(const std::string&s,const std::string&dflt=”“)const
{
prop\u map\u citer found=props.find(s);
return found!=props.end()?found->second:dflt;
}
};
int main()
{
常量配置=
{
{“OutputFile”,“/tmp/out.txt”}
,{“CaptureFPS”,“25.0”}
,{“RetryDelaySeconds”,“5”}
};
std::字符串s;
浮动f;
int i;
s=cfg.get(“输出文件”);
f=cfg.get(“CaptureFPS”);
i=cfg.get(“RetryDelaySeconds”);
std::cout你想做什么?你能让一个类有一个int
double
和string
,然后做一个普通的构造函数吗?你可以把所有的值存储为string,然后有get()
方法返回转换为相关类型的字符串。我希望允许灵活的配置,例如从.yaml文件中读取。值的类型不同{int,double,string},因此常规映射不起作用。对于固定数量的普通类型(如int
和double
,但不是std::string
),您可以组合一个简单的有区别的并集,使用值的并集和枚举来给出类型。如果它更复杂(一组无界类型或非平凡类型),然后只使用Boost.Variant。它只是标题,而且很容易重新创建。您可以使用char*
将字符串指针导入联合体。当然,在这种情况下,您需要自己进行内存管理。+1,主要用于重新创建轮子。因为这正是避免Boost的意思。+1如果您选择重新创建e轮通过有区别的联合。它看起来像boost::property_树