您正在使用C ++中的哪个Typesafe枚举?

众所周知,C ++中的内置枚举不是类型安全的。我想知道在那里使用了哪些实现类型安全枚举的类……我本人使用以下“自行车”,但是它有些冗长和有限:


typesafeenum.h:


struct TypesafeEnum

{

// Construction:

public:

    TypesafeEnum(): id (next_id++), name("") {}

    TypesafeEnum(const std::string& n): id(next_id++), name(n) {}


// Operations:

public:

    bool operator == (const TypesafeEnum& right) const;

    bool operator != (const TypesafeEnum& right) const;

    bool operator < (const TypesafeEnum& right) const;


    std::string to_string() const { return name; }


// Implementation:

private:

    static int next_id;

    int id;

    std::string name;

};

typesafeenum.cpp:


int TypesafeEnum::next_id = 1;


bool TypesafeEnum::operator== (const TypesafeEnum& right) const 

{ return id == right.id; }


bool TypesafeEnum::operator!= (const TypesafeEnum& right) const 

{ return !operator== (right); }


bool TypesafeEnum::operator< (const TypesafeEnum& right) const  

{ return id < right.id; }

用法:


class Dialog 

{

 ...

    struct Result: public TypesafeEnum

    {

        static const Result CANCEL("Cancel");

        static const Result OK("Ok");

    };



    Result doModal();

 ...

};


const Dialog::Result Dialog::Result::OK;

const Dialog::Result Dialog::Result::CANCEL;

另外: 我认为我应该更具体地说明这些要求。我将尝试总结一下:


优先级1:毫无例外,将枚举变量设置为无效值应该是不可能的(编译时错误)。


优先级2:应该可以通过单个显式函数/方法调用将枚举值与int转换。


优先级3:尽可能紧凑,优雅,方便的声明和使用


优先级4:将枚举值与字符串进行相互转换。


优先级5 :(很高兴)迭代枚举值的可能性。


慕工程0101907
浏览 632回答 3
3回答

德玛西亚99

一个不错的折衷方法是这样的:struct Flintstones {&nbsp; &nbsp;enum E {&nbsp; &nbsp; &nbsp; Fred,&nbsp; &nbsp; &nbsp; Barney,&nbsp; &nbsp; &nbsp; Wilma&nbsp; &nbsp;};};Flintstones::E fred = Flintstones::Fred;Flintstones::E barney = Flintstones::Barney;从版本上来说,它不是类型安全的,但是用法比标准枚举更好,并且在需要时仍可以利用整数转换。

千万里不及你

我个人使用的是typesafe枚举用法的改编版本。它没有提供您在编辑中陈述的所有五个“要求”,但无论如何我还是非常不同意其中的一些。例如,我看不到Prio#4(将值转换为字符串)与类型安全有何关系。无论如何,大多数时间字符串表示形式的单个值都应与类型的定义分开(考虑一下i18n的简单原因)。Prio#5(迭代,它是可选的)是我想看到的枚举中自然发生的最好的事情之一,因此令您感到遗憾的是,它在您的请求中显示为“可选”,但似乎可以通过以下方式更好地解决一个单独的迭代系统,例如begin/end 函数或enum_iterator,这使它们可与STL和C ++ 11 foreach无缝协作。OTOH这个简单的成语很好地提供了Prio#3 Prio#1,这是因为它实际上只会包装enum带有更多类型信息的。更不用说这是一个非常简单的解决方案,在很大程度上不需要任何外部依赖标头,因此很容易携带。它还具有使枚举范围为a-la-C ++ 11的优点:// This doesn't compile, and if it did it wouldn't work anywayenum colors { salmon, .... };enum fishes { salmon, .... };// This, however, works seamlessly.struct colors_def { enum type { salmon, .... }; };struct fishes_def { enum type { salmon, .... }; };typedef typesafe_enum<colors_def> colors;typedef typesafe_enum<fishes_def> fishes;解决方案提供的唯一“漏洞”是,它无法解决无法阻止enum将不同类型的s(或an enum和int)直接进行比较的事实,因为直接使用值时会强制执行隐式转换至int:if (colors::salmon == fishes::salmon) { .../* Ooops! */... }但是到目前为止,我发现可以通过简单地与编译器进行更好的比较来解决这些问题,例如,显式提供一个可以比较任意两种不同enum类型的运算符,然后强制其失败:// I'm using backports of C++11 utilities like static_assert and enable_iftemplate <typename Enum1, typename Enum2>typename enable_if< (is_enum<Enum1>::value && is_enum<Enum2>::value) && (false == is_same<Enum1,Enum2>::value) , bool >::type operator== (Enum1, Enum2) {&nbsp; &nbsp; static_assert (false, "Comparing enumerations of different types!");}尽管到目前为止似乎还没有破坏代码,并且确实可以不处理其他问题而明确地处理特定问题,但是我不确定这是“ 应该 ”做的事情(我怀疑它会干扰enum已参与其他地方声明的转换运算符;我很乐意收到对此的评论)。将此与上面的类型安全习惯相结合,就可以enum class在操作性(可读性和可维护性)方面相对接近C ++ 11 ,而不必做任何过于晦涩的事情。而且我不得不承认这样做很有趣,我从没想过要问编译器是否在处理enums ...
打开App,查看更多内容
随时随地看视频慕课网APP