使用C++11可变参数模板初始化枚举到字符串映射

3

我认为在C++11中引入的可变模板参数可以用于初始化一个map,其中键是整数,值是给定参数的字符串表示。

如果可能的话,我可以像这样简单地创建一个从枚举名称到其字符串表示的映射:

auto map = EnumStringMap<EnumType::Type1, EnumType::Type2>();

我可以通过这个模板使用枚举int表示来初始化列表

template<typename... Ts> auto enumList(Ts... args){
    QList<int> res = {args...};
    return res;
}

auto enums =  enumList<int, int>(Enums::Enum1, Enums::Enum2);

我认为使用STRINGFY C宏可以得到表达式的字符串表示。
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)

但我无法弄清如何将类型名称或类型值转换为其字符串表示形式,所以这是否可能呢? 我的目标是在编译时生成一个包含枚举的字符串表示的映射表。
像Qt使用的MOC这样的方法对我来说不适用,因为我应该将枚举项包含在QObject中,这很重且不可复制。

据我所知,在C++中不可能实现。虽然在C#中是可能的。我会自己创建这样的映射(静态)EnumStringMap<EnumType, std::string> - vahancho
2
BETTER_ENUMS这样的库通常使用宏来定义枚举(在我们拥有反射之前)。 - Jarod42
@vahancho 对于大量的枚举(可能超过500个),手动维护非常困难。 - e.jahandar
1个回答

3

宏是由预处理器在任何C++编译之前处理的。因此,您不能在函数内部使用宏来检索枚举值的C++名称。

大多数解决方案基于在定义枚举时使用宏。互联网上有许多可用的实现,通常会执行以下操作:

#define MY_ENUM(a, b, c) enum a {b , c} \
Map<a, string> mymap = {{b, STRINGIFY(b)}, {b, STRINGIFY(b)}};

MY_ENUM(Color, Red, Blue)
MY_ENUM(Align, Left, Right)

另一种方法是使用元编译器,它将处理C++代码以生成更多代码。这就是Qt使用其moc的方式,由于您在问题中标记了Qt,因此这可能是您最好的选择。

class FooBar : public QObject {
  Q_OBJECT
public:
  enum Action { Open, Save, New, Copy, Cut, Paste, Undo, Redo, Delete };
  Q_ENUM(Action) // Not Q_ENUMS !!!

  static QString convert(Action a) {
    auto metaEnum = QMetaEnum::fromType<Action>();
    return metaEnum.valueToKey(a);
  }
};

这里有一些限制,例如枚举必须在 QObject (或者 Q_GADGET) 中定义。您可以在Qt文档中找到更多信息。关于如何实现它,可以参考Woboq的文章


谢谢,我忘了提到我知道Qt使用的方法,但是枚举应该被封装在QObject中,这是不希望的。 - e.jahandar
1
@e.jahandar 你可以使用 Q_GADGET,它比 QObject 更轻量级,但也不是完美的选择。要获得完整的 C++ 支持,您需要等待 C++2x。如果您感兴趣,请参见 Herb Sutter 在 CppCon2017 上的演讲。 - Benjamin T

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接