使用constexpr对非const成员有效

时间:2013-06-28 09:08:00

标签: c++ c++11 enums constexpr

背景

我正在努力实现的目标:我正在尝试实现类似Java枚举的东西(即具有一些附加功能的枚举)。我想出了一个使用两个类的解决方案,其中一个类表示一个值,另一个类充当可能值的枚举,使用静态变量来表示每个值。我希望它是枚举的真正替代品,包括在模板实例化中使用枚举值的可能性。为此,枚举值必须是常量表达式(constexpr)。但是,我不确定我是否正确使用了constexpr。

代码

以下是我提出的代码:

class EnumType {
public:
    enum Enum {val_A, val_B, val_C};

    friend class EnumTypeList;

    EnumType()
    : m_ID(val_A), m_foo(0) {}

    constexpr operator Enum() const {return m_ID;};
    constexpr unsigned int getFoo() const {return m_foo;};
protected:
    constexpr EnumType(const Enum v, const int foo)
    : m_ID(v), m_foo(foo) {}
private:
    Enum m_ID;
    int m_foo;
};

class EnumTypeList {
public:
    static constexpr EnumType A = EnumType(EnumType::val_A, 5);
    static constexpr EnumType B = EnumType(EnumType::val_B, 4);
    static constexpr EnumType C = EnumType(EnumType::val_C, 8);
};

EnumType保存每个值的信息并提供一些附加功能(这里存储可以使用getFoo()函数访问的附加值m_foo)。枚举本身由包含静态constexpr变量的EnumTypeList表示,其中每个变量表示枚举的可能值。此代码允许我使用EnumTypeList中的变量代替EnumType::Enum.,甚至可以使用以下代码中的模板:

template <EnumType::Enum T>
class Test {
public:
    void test() {
        std::cout << "Enum is not A" << std::endl;
    }
};

template <>
class Test<EnumType::val_A> {
public:
    void test() {
        std::cout << "Enum is A" << std::endl;
    }
};

int main() {
    Test<EnumTypeList::A> a;
    a.test();

    Test<EnumTypeList::B> b;
    b.test();

    // this shouldn't compile
    /*EnumType x = EnumTypeList::C;
    Test<x> c;
    c.test();*/
}

这正如我所期望的那样 - 我可以在模板实例化中使用EnumTypeList中的值代替EnumType::Enum,如上所示,但我不能用EnumType x = EnumTypeList::C; < / p>

问题

虽然代码正确编译而没有gcc和clang下的任何警告,但我不确定我是否正确使用constexpr。问题是虽然EnumType构造函数和转换运算符operator Enum()是constexpr,但它们都访问不是常量的变量m_IDm_foo(因为我需要赋值运算符)

1 个答案:

答案 0 :(得分:3)

这很好,文字类型的成员可以修改。

为了在常量表达式中使用类型,你必须使用常量参数构造它,但这样做是正常的,因为你这样做了;

static constexpr EnumType A = EnumType(EnumType::val_A, 5);

构造的对象是有效的常量表达式,因此可用于初始化constexpr变量A。您不修改对象的成员,因此它们可以修改并不重要。

Clang特别对常量表达式非常严格,如果你做错了会产生错误。

此对象可用于需要常量表达式的位置:

constexpr EnumType A5(EnumType::val_A, 5);

e.g。

constexpr int i = A5.getFoo();

此对象不能:

EnumType A6(EnumType::val_A, 6);
constexpr int i = A6.getFoo();  // error