C++ 11枚举与类成员和constexpr链接时优化

Dav*_* L. 5 constexpr enum-class lto

在我的项目中,我有很多枚举,需要有与枚举成员相关的其他属性和与枚举类型相关的辅助静态方法.

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

Bellow一个例子(尽可能简化,但我相信所讨论的所有功能都在那里).

MyItem.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;
};
Run Code Online (Sandbox Code Playgroud)

我认为意思是显而易见的,我不需要在这里提供.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();
};
Run Code Online (Sandbox Code Playgroud)

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

MyItemEnum::Item1.getExt()
Run Code Online (Sandbox Code Playgroud)

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

static constexpr MyItemEnum Item1 = MyItemEnum(MyItem::Item1, 123);
Run Code Online (Sandbox Code Playgroud)

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

jst*_*ine 0

我还没有使用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;
};
Run Code Online (Sandbox Code Playgroud)

需要注意的是,构造函数必须使用 C++ 样式的初始值设定项列表语法,如果您只是用常量值填充它们,那么这应该不是问题。(只有在需要进行重要设置时,初始化列表才会变得很痛苦)。

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