【问题标题】:Proper way to convert std::string to/from enum class [duplicate]将 std::string 转换为/从枚举类的正确方法 [重复]
【发布时间】:2021-04-13 04:01:34
【问题描述】:

对于我目前正在处理的作业,我为不同的学期定义了一个枚举类。

enum class Semester {
        FALL,
        SPRING,
        SUMMER
};

在我重载的<< 运算符中,我将打印出与Semester 类型等效的小写字符串。我已经通过使用Semester 键和std::string 对创建映射来做到这一点:

std::map<Semester, std::string> to_string
{
        {Semester::FALL, "fall"},
        {Semester::SPRING, "spring"},
        {Semester::SUMMER, "summer"}
};

std::stream& operator <<(std::stream& ost, enum Semester semester)
{
        return ost << ::to_string[semester];
}

我已经不确定之前的解决方案是否是最优的,所以我开始着手下一个任务,即定义Semester load_semester(std::istream&amp; ist)。此函数接收来自用户的输入为std::string(我想我会使用std::getline())并将其转换为Semester 类型。我想我可以使用类似于之前的地图,但我很好奇解决这个问题的“正确”方法是什么。

编辑:感谢您的反馈!我将按照@casey 的建议实现功能。

我正在为学期和部分(即数学、阅读、科学等)实施枚举课程。将来我可能需要实施更多。我能否以可以重用它们的方式实现这些功能?

【问题讨论】:

  • 我认为您在学习时不应该担心“最佳”代码。通常情况下,您会被无关的性能问题所困扰,以至于在实际功能上没有任何进展,或者最终陷入难以调试的奇怪问题。地图很好,但更常见的方法是只使用数组。通过您当前使用此映射的方式,您不会在这里获得太多收益,除非您的枚举是范围之外的值,您的映射将隐式 add 新的空字符串,而未经检查的数组访问会导致未定义的行为。
  • 我很好奇解决这个问题的“正确”方法是什么。就像编程中的许多事情一样,这是一个见仁见智的问题。

标签: c++ string dictionary input enums


【解决方案1】:

不要打扰std::map,只需使用一个函数:

//As an aside, avoid uppercase enum names
enum class Semester {
    Fall,
    Spring,
    Summer
};

std::string to_string(const Semester& s) {
    switch(s) {
        case Semester::Fall: return "fall";
        case Semester::Spring: return "spring";
        case Semester::Summer: return "summer";
        default: throw std::exception("to_string: Semester enum values have changed.");
    }
}

Semester from_string(std::string str) {
    std::transform(std::begin(str), std::end(str), std::begin(str), [](unsigned char c)->unsigned char { return std::tolower(c); });
    if(str == "fall") {
        return Semester::Fall;
    } else if(str == "spring") {
        return Semester::Spring;
    } else if(str == "summer") {
        return Semester::Summer;
    } else {
        throw std::exception("from_string: Semester enum values have changed.");
    }
}

std::ostream& operator<<(std::ostream& ost, const Semester& semester) {
    ost << to_string(semester);
    return ost;
}

【讨论】:

  • 为什么函数比地图更好?
  • 有人可能会争辩说地图使用了不必要的内存。但是,保留两组字符串存在维护问题。我个人使用单个表进行枚举到字符串的查找,并在同一个表中搜索字符串到枚举的查找。同样,关于设计要求、项目动机、枚举数等等……这确实是一个基于意见的问题,这就是为什么我没有回答它。
  • @JohnKugelman 见 paddy 的评论。 :) 所有的优点。对于包含 数百个 值的枚举,我已经完成了上述操作。
  • :-) 我对此有一个问题,当事情失败时,它会抛出而不是将流设置为失败状态。
  • @TedLyngmo 在枚举值更改时大声失败,非常清楚地表明“嘿,不要忘记也更改这些函数!”
猜你喜欢
  • 2011-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-07
  • 1970-01-01
  • 2013-03-23
  • 2013-05-11
  • 2013-09-10
相关资源
最近更新 更多