带有方法和静态实例的C ++ 11枚举的成语?

问题描述

我想执行以下操作(不会编译):

class Foo {
    int value;

    Foo(const int arg)
        : value{arg}
    {}

public:    
    static const Foo a{0};
    static const Foo b{1};
    static const Foo c{2};

    Foo func(const Foo& foo) {...}
};

以便严格控制Foo的实例(例如在enum中),以便我可以编写类似auto foo = Foo::a;auto foo = Foo::a.func(Foo::b);代码

不幸的是,由于静态实例的类型不完整,因此代码无法在C ++ 11下编译。

有这个成语吗?

解决方法

您可以很容易地做到这一点,但是需要将常量的定义放在类之外:

class Foo {
    int value;

    // In C++17,you could make this constexpr.
    Foo(const int arg)
        : value{arg}
    {}

public:
    // in C++20,you could make these constinit.
    static const Foo a;
    static const Foo b;
    static const Foo c;
};

// In C++11 these need to go in the source file to avoid linker errors.
// In C++17 you could make them inline and put them in the header.
// In C++20 you could make them constinit.
const Foo Foo::a = 0;
const Foo Foo::b = 1;
const Foo Foo::c = 2;

不过,我不会将其称为一个优雅的解决方案。特别是在C ++ 11中,编译器无法内联这些常量,因为它们需要进入源文件。这会对性能产生重大影响。因此,如果您要这样做,我建议至少使用C ++ 17,如果不是C ++ 20。

通常,C ++枚举应为整数常量,不像Java中那样支持获取enum的序数或名称。另一种方法是使用没有值的enum class(默认值为0、1、2,...),然后将它们用作查找表中的索引。

使用switch作为属性也可以达到目的:

enum class Axis : unsigned { X,Y,Z };

// in C++17,you could make this constexpr.
inline const char *nameOf(Axis axis)
{
    switch (axis) {
    case Axis::X: return "X";
    case Axis::Y: return "Y";
    case Axis::Z: return "Z";
    }
}