当前位置:  开发笔记 > 编程语言 > 正文

您使用C++中的哪种Typesafe枚举?

如何解决《您使用C++中的哪种Typesafe枚举?》经验,为你挑选了4个好方法。

众所周知,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或从int转换.

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

优先级4:将字符串值转换为字符串和从字符串转换.

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



1> Josh Kelley..:

我目前正在玩Boost Vault(文件名enum_rev4.6.zip)中的Boost.Enum提案.虽然它从未正式提交过包含在Boost中,但它可以原样使用.(缺少文档,但是通过明确的源代码和良好的测试来弥补.)

Boost.Enum允许你声明这样的枚举:

BOOST_ENUM_VALUES(Level, const char*,
    (Abort)("unrecoverable problem")
    (Error)("recoverable problem")
    (Alert)("unexpected behavior")
    (Info) ("expected behavior")
    (Trace)("normal flow of execution")
    (Debug)("detailed object state listings")
)

并让它自动扩展到:

class Level : public boost::detail::enum_base
{
public:
    enum domain
    {
        Abort,
        Error,
        Alert,
        Info,
        Trace,
        Debug,
    };

    BOOST_STATIC_CONSTANT(index_type, size = 6);

    Level() {}
    Level(domain index) : boost::detail::enum_base(index) {}

    typedef boost::optional optional;
    static optional get_by_name(const char* str)
    {
        if(strcmp(str, "Abort") == 0) return optional(Abort);
        if(strcmp(str, "Error") == 0) return optional(Error);
        if(strcmp(str, "Alert") == 0) return optional(Alert);
        if(strcmp(str, "Info") == 0) return optional(Info);
        if(strcmp(str, "Trace") == 0) return optional(Trace);
        if(strcmp(str, "Debug") == 0) return optional(Debug);
        return optional();
    }

private:
    friend class boost::detail::enum_base;
    static const char* names(domain index)
    {
        switch(index)
        {
        case Abort: return "Abort";
        case Error: return "Error";
        case Alert: return "Alert";
        case Info: return "Info";
        case Trace: return "Trace";
        case Debug: return "Debug";
        default: return NULL;
        }
    }

    typedef boost::optional optional_value;
    static optional_value values(domain index)
    {
        switch(index)
        {
        case Abort: return optional_value("unrecoverable problem");
        case Error: return optional_value("recoverable problem");
        case Alert: return optional_value("unexpected behavior");
        case Info: return optional_value("expected behavior");
        case Trace: return optional_value("normal flow of execution");
        case Debug: return optional_value("detailed object state listings");
        default: return optional_value();
        }
    }
};

它满足您列出的所有五个优先级.


我最初设计的boost :: enum是一个在编译时构建的字符串表,可以在运行时使用.最终它变成了一个更通用的类型安全枚举.由于我没有时间专注于文档,它从未被包含在提升中.很高兴在野外看到它!
不需要爆炸头; 复杂性很好地隐藏在宏和一个干净的界面背后.标准C枚举有几个实际问题:缺乏类型安全性,无法查询枚举类型的最大大小,缺少自动转换到字符串/从字符串转换.
这看起来非常有用,您仍然应该尝试使用它.也许是使用新的C++ 0x强类型枚举的版本(仍然很高兴获得boost :: optional接口和字符串转换).
版本4.6中的BOOST_ENUM不完全是类型安全的,即涉及operator ==()时.例如BOOST_ENUM(Apple,(a)); BOOST_ENUM(橙色,(○)); bool x = Apple(Apple :: a)== Orange :: o; 编译得很好.原因是ctor enum_base(index_type index)不是显式的,index_type等于int.不确定其他运营商.

2> Charlie..:

一个很好的折衷方法是:

struct Flintstones {
   enum E {
      Fred,
      Barney,
      Wilma
   };
};

Flintstones::E fred = Flintstones::Fred;
Flintstones::E barney = Flintstones::Barney;

它与您的版本在同一意义上不是类型安全的,但是它的用法比标准枚举更好,并且您仍然可以在需要时利用整数转换.


使用命名空间而不是结构,这不是更清晰吗?
c ++ 11枚举类使这完全是多余的
命名空间事件的后续操作:对于存在于类或结构中的枚举,您不能使用命名空间.如果枚举*不存在于类或结构中,我认为使用命名空间更清晰是正确的.

3> Roddy..:

我使用C++ 0x typesafe枚举.我使用一些帮助模板/宏来提供来自/来自字符串的功能.

enum class Result { Ok, Cancel};



4> 小智..:

我不.太多的开销太少了.此外,能够将枚举分类到不同的数据类型以进行序列化是一个非常方便的工具.我从来没有见过一个实例,其中"类型安全"枚举值得开销和复杂性,其中C++已经提供了足够好的实现.


可以使用模板实现类型安全枚举,使得不存在任何运行时开销.如果你使用say,BOOST_ENUM,所有复杂性都在库中.
推荐阅读
郑谊099_448
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有