【问题标题】:How to output enum elements using cout?如何使用 cout 输出枚举元素?
【发布时间】:2021-09-01 08:38:52
【问题描述】:

我正在尝试输出我声明的枚举元素,但例如,当我输入 push_ups 时,它会输出一个类似 8621623 的数字,而不是显示 push_ups。我不知道为什么。我是日本人,所以如果我的英语不好,我很抱歉。非常感谢。

#include <iostream>
#include <string>
using namespace std;

enum exercise { push_ups, sit_ups, squats, walking, radio_calisthenics };

istream& operator>>(istream& is, exercise& i)
{
    int tmp;
    if (is >> tmp)
        i = static_cast<exercise>(tmp);
    return is;
}

int main()
{
    exercise a;
    cin >> a;
    cout << a << endl;
}

【问题讨论】:

  • 等等,澄清一下,你到底输入了什么?如果您输入了字符串“push_ups”,请注意这对算法没有意义。最有可能的是,您需要输入类似 0 的内容来获取枚举值 push_ups。枚举不携带字符串值。

标签: c++ enums


【解决方案1】:

我正在尝试输出我声明的枚举元素,但例如,当我输入push_ups 时,它会输出一个类似8621623 的数字,而不是显示push_ups

operator&gt;&gt; 重载中,std::cin 接受整数,所以push_ups 不是整数,所以std::cin 将失败,并且i = static_cast&lt;exercise&gt;(tmp); 行将被跳过以生成@ 987654330@ uninitialized 打印时会导致 Undefined Behavior 发生。

如果您想将 strings 映射到相应的枚举值,您可以使用哈希映射手动将每个字符串映射到相应的枚举值(在 C++ 中,该容器称为 std::unordered_map) :

#include <unordered_map>

// ...

const unordered_map<string, exercise> exercise_map {
    { "push_ups", push_ups },
    { "sit_ups", sit_ups },
    { "squats", squats },
    { "walking", walking },
    { "radio_calisthenics", radio_calisthenics }
};

istream& operator>>(istream& is, exercise& i) {
    std::string tmp;
    if (is >> tmp) {
        auto const it = exercise_map.find(tmp);
        if (it != exercise_map.end())
            i = it->second;
    }
    return is;
}

现在,要从枚举中打印出相应的 string 值,我们必须做相反的事情,即使用该值在 hashmap 中找到键:

ostream& operator<<(ostream& os, exercise& i) {
    auto const it = std::find_if(exercise_map.begin(), exercise_map.end(),
        [i](std::pair<std::string, exercise> const& e) {
            return e.second == i;
        }
    );
    if (it != exercise_map.end())
        os << it->first;
    return os;
}

完整的代码应该是这样的:

#include <unordered_map>
#include <algorithm>
#include <utility>
#include <iostream>
#include <string>

using namespace std;

enum exercise { push_ups, sit_ups, squats, walking, radio_calisthenics };

const std::unordered_map<std::string, exercise> exercise_map {
    { "push_ups", push_ups },
    { "sit_ups", sit_ups },
    { "squats", squats },
    { "walking", walking },
    { "radio_calisthenics", radio_calisthenics }
};

istream& operator>>(istream& is, exercise& i) {
    std::string tmp;
    if (is >> tmp) {
        auto const it = exercise_map.find(tmp);
        if (it != exercise_map.end())
            i = it->second;
    }
    return is;
}

ostream& operator<<(ostream& os, exercise& i) {
    auto const it = std::find_if(exercise_map.begin(), exercise_map.end(),
        [i](std::pair<std::string, exercise> const& e) {
            return e.second == i;
        }
    );
    if (it != exercise_map.end())
        os << it->first;
    return os;
}

int main() {
    exercise a;
    cin >> a;
    cout << a << endl;
}

【讨论】:

    【解决方案2】:

    push_ups 不是您尝试在is &gt;&gt; tmp 读取的有效整数值,因此a 保持未初始化状态。如果要输入名称,则需要读取字符串,然后手动将其转换为相应的枚举值。输出也一样。如果没有正确重载的运算符 a 将被视为整数。

    【讨论】:

      【解决方案3】:

      这里的这一行:

      i = static_cast<exercise>(tmp);
      

      当 tmp 保持 0 到 4 之间的 int 值时,将完美运行,

      但在您的情况下 tmp = push_ups 正在破坏强制转换操作,并且您的 ref i 被错误地初始化

      【讨论】:

        【解决方案4】:

        您似乎对enums 的理解有问题。
        我认为您输入了字符串值“push_ups”并假设程序会理解它以引用您的 enum 的值。
        enum 只是整数类型的占位符,主要用于增加程序的可读性。

        查看枚举是一种更好的表达方式

        // chess_piece = 1 : pawn
        // chess_piece = 2 : rook
        // chess_piece = 3 : bishop
        ...
        int chess_piece;
        

        作为

        enum ChessPiece { Pawn, Rook, Bishop, ...};
        ChessPiece chess_piece;
        

        在上面的变体中,很明显 pawn、rook 等名称仅注释enum 在这方面没有什么不同。显然写成if(chess_piece == Pawn) 更易读,但是“Pawn”这个词只是编程语言中代码的一部分,编译后的程序中没有。它不作为字符串值存在。

        你可以做的是添加类似的东西

        exercise exercise_from_string(const std::string& input)
        {
             if(input == "push_ups") return push_ups;
             ...
        

        或与开关相同。我还建议您使用“未知”值,以防这样的函数找不到已知术语。

        编辑:当我写这篇文章时,其他一个人更新了他的答案,他使用 std::map 的代码比我的要好。
        不过,希望我的回答能帮助您理解核心问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-22
          • 1970-01-01
          • 2018-05-27
          • 2021-12-19
          • 1970-01-01
          • 2020-05-04
          相关资源
          最近更新 更多