5

在我的项目中,我有很多枚举需要具有与枚举成员关联的附加属性以及与枚举类型关联的辅助静态方法。

据我所知,标准枚举类 MyItem {...} 是不可能的,因此对于我项目中的每个枚举类,我都有一个辅助类 MyItemEnum,它封装了这些辅助静态方法并实例化了本身,这样我就可以访问他们的方法以获得额外的属性。

下面举个例子(尽可能简化,但我相信要讨论的所有功能都保留在那里)。

我的项目.h

enum class MyItem : unsigned int {
    Item1   = 1,
    Item2   = 5
};

class MyItemEnum {
private:
    MyItem myItem;
    size_t extInfo;

    MyItemEnum(const MyItem& myItem, size_t extInfo);
    ~MyItemEnum();
public:
    static MyItemEnum Item1;
    static MyItemEnum Item2;
    static const MyItemEnum &get(MyItem myItem);

    operator MyItem() const;
    size_t getExt() const;
    bool hasNext() const;
    MyItem next() const;
};

我认为含义很明显,我不需要在此处提供 .cpp 部分...当我需要访问扩展功能时,我使用 MyItem 作为要在接口和 MyItemEnum 中传递的参数。

我的第一个问题是,上面的方法可以吗,还是我应该考虑完全不同的东西?

我的第二个问题涉及我尝试使用 constexpr 对这个枚举进行优化:

enum class MyItem : unsigned int {
    Item1   = 1,
    Item2   = 5
};

class MyItemEnum {
private:
    MyItem myItem;
    size_t extInfo;

    constexpr MyItemEnum(const MyItem& myItem, size_t extInfo);
public:
    static MyItemEnum Item1;
    static MyItemEnum Item2;
    static constexpr MyItemEnum &get(MyItem myItem);

    constexpr operator MyItem();
    constexpr size_t getExt();
    constexpr bool hasNext();
    constexpr MyItem next();
};

它可以编译,但显然 constexpr 没有机会被使用,因为如果我访问:

MyItemEnum::Item1.getExt()

所以编译器不知道 Item1 用什么值来实例化。 在链接时间优化期间,上面的表达式是否有可能被评估为 constexpr? 或者我可以使用

static constexpr MyItemEnum Item1 = MyItemEnum(MyItem::Item1, 123);

这将激活 constexpr 编译时优化,但我担心在某些情况下,当 constexpr 无法在编译时评估时,编译器将不得不创建 MyItemEnum 的本地实例(而不是使用对单个全局的引用静态实例)并且我担心这可能会导致性能损失(我的真实枚举具有比单个成员更多的属性,因此本地实例化可能需要一些时间?)。这是一个合理的担忧吗?

4

1 回答 1

0

我还没有直接使用 ofconstexpr和由此产生的编译器优化的经验,但我可以告诉你,只需const在类本身的成员或实例上使用 VS2012 和 g++ 4.7 编译器即可进行跨模块优化:

class MyItemEnum {
private:
    // make sure to put const here...
    const MyItem myItem;
    const size_t extInfo;

    MyItemEnum(const MyItem& myItem, size_t extInfo);
    ~MyItemEnum();
public:
    // and put const in here too...
    static const MyItemEnum Item1;
    static const MyItemEnum Item2;
};

需要注意的是,构造函数必须使用 C++ 风格的初始化列表语法,如果你只是用常量值填充它们,这应该不是问题。(初始化列表只有在需要非平凡设置时才会变得痛苦)。

我没有在 Clang/LLVM 上验证这一点,所以如果那是你的工具链,那么我强烈建议你采用这个简化的例子并自己取消结果。即使您不熟悉汇编语言,对简单测试用例的反汇编也很容易解析。在这种情况下,您可以编译两个版本:一组在一个模块中,一个分为两个模块 - 并比较结果以确保 LTO 正在完成您需要的工作。

于 2012-12-30T16:18:11.480 回答