将枚举值转换为字符串

Convert enum values to strings

提问人:David Hovsepyan 提问时间:11/9/2023 最后编辑:HolyBlackCatDavid Hovsepyan 更新时间:11/9/2023 访问量:176

问:

我有以下代码片段:

enum class Code : uint8_t
{
    A = 0,
    B = 1,
    C = 2
}

如何向枚举添加转换运算符(或类似的东西,如果可能的话),以便当我将枚举对象传递给接受的函数时,对象将被隐式转换为 。 目的是将字符串、等转换为字符串。std::stringstd::string0"0"1"1"

注意:我不想添加这样的功能,例如, 因为我需要隐式转换toString

++ 的 C++11

评论

5赞 HolyBlackCat 11/9/2023
你能做的最好的事情是用一个假装是枚举的类替换枚举,并向其添加一个转换运算符。
0赞 David Hovsepyan 11/9/2023
@HolyBlackCat 问题是枚举类型稍后被传递给一些共享/泛型函数,例如执行以下操作: 所以,我想,我不被允许将枚举更改为类。为什么无法为枚举类型定义转换运算符。FromEnumstatic_cast<typename std::underlying_type<Enum>::type>(enumValue);std::string
1赞 Dima Chubarov 11/9/2023
@DavidHovsepyan您上面的评论为该问题带来了重要的背景。你能在你的帖子中添加一个预期用途的例子吗?
2赞 HolyBlackCat 11/9/2023
不能将转换运算符添加到枚举 Period。您的选择是:1.将枚举替换为类,2.将参数替换为可以接受枚举(或其他东西)的包装类,3。根本不进行隐式转换。std::string
2赞 n. m. could be an AI 11/9/2023
“我需要隐式转换”请重新考虑这一点。隐式转换是我们所有人都可以没有的语法糖,因为它们通常会导致难以发现的错误。

答:

2赞 mitch_ 11/9/2023 #1

我最初发布了一个示例,说明如何使用一些隐式转换技巧来实现这一点,但意识到这可以进一步简化。

我假设你写了你想要将类型传递给的方法;然后,最简单的选择是添加一个简单的重载,该重载也接受 ,执行到 的转换,然后将结果传递给另一个方法,例如CodeCodestd::string

void work(std::string);

/* adding.... */
void work(Code c)
{
  switch (c)
  {
    case Code::A: return work("A");
    case Code::B: return work("B");
    case Code::C: return work("C");
    default: __builtin_unreachable();
  }
}

如果该方法是标准库的一部分,我相信在这里添加您自己的重载将是 UB,但是您可以在新的命名空间中引入它并使用 ADL 来找出其余部分。

最好的答案最终将取决于你所处的确切情况,但这可能是一个很好的起点。

评论

4赞 Toby Speight 11/9/2023
而不是 ,通常最好将调用放在 之后,这样我们就不会丢失编译器检查是否考虑了所有值。default:std::unreachable();switch
0赞 kiner_shah 11/9/2023
@TobySpeight问题提到标记C++ 11,std::unreachable 来自C++ 23。
1赞 mitch_ 11/9/2023
正确,但注释更多的是此处不应包含默认分支,并且调用应在交换机之外,以便更好地发出警告__builtin_unreachable
2赞 Toby Speight 11/9/2023 #2

我不确定你为什么需要这个,所以我的建议可能很宽泛。但是,如果你需要一个可以被视为 a 或字符串的值,那么我们可以创建一个包装类,它将转换为以下任一:Code

struct Code_class
{
    Code c;

    Code_class(Code c) : c{c} {}

    operator Code() const
    {
        return c;
    }

#define X(x) case Code::x: return #x
    operator std::string() const
    {
        switch (c) {
            X(A);
            X(B);
            X(C);
        }
        std::unreachable();
    }
#undef X
};

完整演示

#include <cstdint>
#include <string>
#include <utility>

enum class Code : uint8_t
{
    A = 0,
    B = 1,
    C = 2
};

struct Code_class
{
    Code c;

    /* implicit */ Code_class(Code c) : c{c} {}

    operator Code() const
    {
        return c;
    }

#define X(x) case Code::x: return #x
    operator std::string() const
    {
        switch (c) {
            X(A);
            X(B);
            X(C);
        }
        std::unreachable();
    }
#undef X
};

#include <iostream>
int main()
{
    auto m = Code::A;

    Code_class p = m;
    const std::string s = p;

    std::cout << s << '\n';
}

评论

0赞 alagner 11/9/2023
我本着类似的精神写答案;)但后来我意识到样板代码可能会变得有点大,难以维护:来自枚举的额外赋值、比较等。
1赞 mitch_ 11/9/2023
有趣的是,我们最初是如何聚集在相同的想法上的!这里的主要缺点是,执行此转换仍然需要一个显式步骤,因为原始类型不能传递给接受 a 的方法,而没有显式命名此处的构造函数,这相当于具有 OP 旨在避免的方法。Codestd::stringCode_classtoString
-1赞 Jakkapong Rattananen 11/9/2023 #3

char 是一种整数,因此我们可以声明 char 的枚举。

#include <iostream>

enum struct Cnum : char { h = 'h', o = 'o', e = 'e', l = 'l' , num_0 = '0' };

std::ostream& operator<<(std::ostream& os, Cnum c) {
    os << static_cast<char>(c);
    return os;
}

int main() {
    std::cout << Cnum::h << Cnum::e << Cnum::l << Cnum::l << Cnum::o << Cnum::num_0 << "\n";//print hello0
}

然后你可以稍后从 char 构建字符串。

评论

1赞 mitch_ 11/9/2023
我的假设是,OP 想要一个通用解决方案,该解决方案甚至适用于名称更复杂的成员。此外,枚举值的值可能需要为 0,但具有不同的字符串表示形式。