【问题标题】:Is there a good way to combine or simplify these STL maps?有没有一种好方法可以组合或简化这些 STL 映射?
【发布时间】: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


【解决方案1】:

下面的模板类怎么样:

template<typename ValueType>
class UnorderedStringMap : public std::unordered_map<std::string, ValueType> {
 public:
  ...
  void setValue(const std::string &varName, ValueType newVal) {
    std::unordered_map::operator[](varName) = newVal;
  }
  const ValueType& getValue(const std::string &varName) {
    return std::unordered_map::operator[](varName);
  }
  ...
}

UnorderedStringMap<int> myInts;
UnorderedStringMap<float> myFloats;

然后您也可以将其用作普通的 std::unordered_map。

【讨论】:

  • 我想这可能是消除所有这些 get-set 方法的最佳方法,谢谢!
猜你喜欢
  • 1970-01-01
  • 2022-11-18
  • 1970-01-01
  • 2015-07-15
  • 2013-03-08
  • 2011-12-22
  • 2011-08-24
  • 1970-01-01
相关资源
最近更新 更多