【发布时间】:2017-01-01 18:32:52
【问题描述】:
我正在编写一个需要存储一堆不同原语和类的类。我决定为每种不同的数据类型制作一个映射,其中映射中的键是变量的名称,映射中的值是变量的值。我的地图是这样定义的:
std::unordered_map<std::string, int> myInts;
std::unordered_map<std::string, float> myFloats;
std::unordered_map<std::string, Something> mySomethings;
对于每张地图,我必须编写两种方法,一种用于获取某个变量的值,另一种用于设置某个变量的值,如下所示:
void setMyInt(const std::string &varName, int newVal) {
myInts[varName] = newVal;
}
int getMyInt(const std::string &varName) {
return myInts[varName];
}
这一切都很好,很容易,但是,我最终得到了 8 个不同的地图,其中 16 个 get set 方法。这对我来说似乎不是很高效或干净,更不用说每次我需要存储新的数据类型时,我都必须定义一个新的映射并编写 2 个新的 get-set 方法。
我考虑摆脱 get set 方法,而是编写 2 个模板方法,它们将接受用户需要获取或设置的变量类型,然后访问正确的 set 以执行操作,如下所示:
template<class Type>
void getVariable<Type>(const std::string &varName) {
// if Type == int -> return myInts[varName];
// else if Type == float -> return myFloats[varName];
}
这似乎是一种非常糟糕的方法,因为用户可以传入该类不支持的类型,并且该方法打破了 C++ 不是真正通用的规则。
我的另一个想法是编写一些变量类,该类将包含该类应存储的所有字段,以及一些定义该类实际用于什么变量的枚举,然后制作该变量类的映射像这样:
enum Type {
TYPE_INT,
TYPE_FLOAT,
TYPE_SOMETHING
class Variable {
Type type;
int myInt;
float myFloat;
Something mySomething;
}
std::unordered_map<std::string, Variable> myVariables;
但这似乎也是一个非常糟糕的解决方案,或者至少是一个难以理解的解决方案。有什么聪明的方法可以让这个类存储不同的类型吗?
【问题讨论】:
-
这似乎是一个非常糟糕的方法,因为用户可以传入该类不支持的类型 -- 您可以使用compile-time assertions 来停止编译错误如果不支持类型。此外,您的
get方法使用[ ]来检索项目。请注意,如果关键项目不存在,地图的[ ]将插入一个新项目。这是你真正想做的吗? -
您是否正在寻找
std::variant?您的Variable似乎是在尝试重塑std::variant。就个人而言,这是我首先想到的方法。 -
@PaulMcKenzie 我之前尝试将模板限制在某些类中,人们建议编译时断言,但其他人也说模板应该是真正通用的,并且这样的断言违反了该规则。
-
@IgorTandetnik 我不知道 boost 库之外还有变体,我会尝试检查一下。
-
模板应该是真正通用的 -- 那么它们如何将这种推理与某些 STL 容器对可以存储的数据类型施加的约束相结合呢?
标签: c++ stl unordered-map