具有类成员和 constexpr 链接时优化的 C++11 枚举

标签 c++ constexpr enum-class lto

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

据我所知,标准枚举类 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 作为要在接口(interface)和 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 的本地实例(而不是使用对单个全局静态实例的引用),我担心这可能会导致性能下降(我的真实枚举具有比单个成员更多的属性,因此本地实例化可能需要一些时间?)。 这是一个合理的担忧吗?

最佳答案

我没有直接使用 constexpr 的经验以及由此产生的编译器优化,但我可以告诉你,只需使用 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 正在完成您需要的工作。

关于具有类成员和 constexpr 链接时优化的 C++11 枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14090583/

相关文章:

构造函数中的 C++14 constexpr union 条件初始化

c++ - 使用Doxygen记录枚举类值而不启用EXTRACT_ALL

c++ - 访问内存中的代码空间?

c++ - 谁负责删除构面?

c++ - 为什么在使用静态 constexpr 成员构造时 std::make_shared 与 new 不同?

c++ - 我可以使用枚举类值作为可变参数函数的参数吗?

c++ - 验证整数是某个枚举类项 (C++11)

c++ - 未定义对 'vtable for class' 的引用

c++ - 合并排序中的递归调用

c++ - 用 const char*const 解释 constexpr