获取和设置C++中的枚举

Get & Set for Enum in C++

本文关键字:枚举 C++ 设置 获取      更新时间:2023-10-16

我有一个名为School的类,它的一个成员是枚举"SchoolType",它有两个可能的值:Primary和Secondary。以下是我在学校头文件中的枚举:

 enum class SchoolType {
    Primary = 1,
    Secondary = 2
};

在我的主C++文件中,我有一个函数ReadSchool,它从用户输入中读取School的所有成员。所有其他成员都是intstring值,所以我在读取这些值时没有问题,但我不知道该如何处理枚举。我最好的想法是这样做:

School ReadSchool()
{
    School tempSchool;
    int type;
    cout << "Name of School: ";
    tempSchool.SetName(GetString());
    cout << endl << "Type of School (1 = Primary, 2 = Secondary): ";
    cin >> type;
    if (type = 2)
        tempSchool.SetTypeSchool(2);        
    else
        tempSchool.SetTypeSchool(1);
    return tempSchool;
}

在我的SetTypeSchool()中放入一个int值是无效的,但写入PrimarySecondary也是无效的。如果有什么不同的话,我使用的是Visual Studio 2015。有人能提供一些清晰度或更好的方法来设置我的枚举值吗?感谢您的帮助

SchoolType GetSchoolType(string input)
{
    // DeHumanize our input
    if(input == "Primary")
    {
        return SchoolType::Primary;
    }
    else if(input == "Secondary")
    {
        return SchoolType::Secondary;
    }
    return SchoolType.None; // or throw an exception, or return a default SchoolType; up to you
}

您的代码有几个问题,例如if (type = 2)应该是if (type == 2)。要传递实际的常量,需要将它们称为SchoolType::PrimarySchoolType::Secondary。如果SetSchoolType的参数的类型是SchoolType,那么它将接受这两个常量。

几个回答者提到了从字符串转换值,包括为此定义流运算符。如果你不反对使用外部库,你可以用这样的语法来实现:

#include <enum.h>
BETTER_ENUM(SchoolType, int, Primary = 1, Secondary = 2)
// ...later...
SchoolType  type;
cin >> type;    // Expects to read the string "Primary" or "Secondary".

其余的用法在很大程度上类似于普通的枚举类。

该库可在以下位置找到:https://github.com/aantron/better-enums.它由一个单独的头文件组成。许可证是BSD,所以可以随心所欲地使用它。有一个Stack Overflow的答案解释了库内部的核心:https://stackoverflow.com/a/31362042/2482998.

由于一个不幸的限制,您将无法如您所描述的那样直接在School中声明SchoolType,但README中显示了一个简单的解决方法。

免责声明:我是作者。

您可以为枚举类型编写流式操作符,之后它们可以自然地与<<>>:一起使用

#include <iostream>
#include <string>
#include <sstream>
enum class SchoolType {
    Primary = 1,
    Secondary = 2
};
std::ostream& operator<<(std::ostream& os, SchoolType s)
{
    return os << (s == SchoolType::Primary ? "Primary" :
                  s == SchoolType::Secondary ? "Secondary" :
                  throw std::runtime_error("invalid SchoolType output"));
}
std::istream& operator>>(std::istream& is, SchoolType& s)
{
    std::string word;
    if (is >> word)
    {
        if (word == "Primary") { s = SchoolType::Primary; return is; }
        if (word == "Secondary") { s = SchoolType::Secondary; return is; }
        is.setstate(std::ios::failbit);
    }
    return is;
}
int main()
{
    std::cout << SchoolType::Primary << ' ' << SchoolType::Secondary << 'n';
    std::istringstream iss("Primary Secondary Fail");
    SchoolType a, b;
    iss >> a >> b;
    std::cout << a << ' ' << b << " good:" << iss.good() << 'n';
    iss >> a;
    std::cout << "good:" << iss.good() << 'n';
}

请参阅此处运行的代码。

注意:简单地流式传输到std::string,然后检查枚举标识符,在使用时需要注意:标识符必须由空格(例如空格、制表符、换行符)或文件结尾分隔;诸如标点符号或括号/大括号/圆括号之类的尾随字符将被吸入字符串中,然后比较将失败并抛出。

这里提供了一个更复杂但健壮的版本,使用支持类Identifier逐个字符输入,并在标识符中不合法的第一个字符处使用unget()。这样,在operator>>(std::istream& is, SchoolType& s)中,只需将std::string word;替换为Identifier word;

struct Identifier : std::string { };
std::istream& operator>>(std::istream& is, Identifier& idn)
{
    idn.clear();
    char c;
    if (is >> c)
    {
        if (!std::isalnum(c))
            is.setstate(std::ios::failbit);
        else
        {
            idn += c;
            while (is.get(c))
                if (std::isalnum(c) || c == '_')
                    idn += c;
                else
                {
                    is.unget();
                    break;
                }
            // hit EOF, is.get(c) will have left fail condition set
            is.clear(); // doesn't matter that we also clear EOF
        }
    }
    return is;
}

(在实践中,我更喜欢写入字符串和from字符串函数,然后使用这些函数编写流运算符:这有时更方便,例如,如果您快速想要一个字符串表示而不创建流)。

您应该允许用户输入字符串(例如"Primary"或"Secondary"),然后使用一个函数将字符串转换为enum

该功能有两个用途:

  1. 验证输入
  2. 执行从stringenum的必要转换

一种方法是替换:

 SetSchoolType(2);

带有

 SetSchoolType(static_cast<SchoolType>(2));