【问题标题】:Is it possible to have enum of enums in c++?是否有可能在 C++ 中有枚举的枚举?
【发布时间】:2013-03-15 08:30:07
【问题描述】:

在 c++ 中是否可以有枚举的枚举。 我必须有类似的东西:

错误类型:

  • 类型1
  • 类型2
  • 类型3

类型1:

  • 原因1
  • 原因2

类型2:

  • 原因3
  • 原因4

类型3:

  • 原因5
  • 原因6

每一个都是整数值。它们应该用于通信协议栈。在接收端,接收器必须从接收到的值中解码错误的类型和原因。如果无法使用枚举,最好的方法是什么?

【问题讨论】:

  • 抱歉,答案是否定的——您需要找到一种不同的方式来做事。一种典型的方法是将类型编码为数字中的一些高位,将原因编码为一些低位(例如,16 位值,每个 8 位)。
  • 不可能有枚举的枚举,但您可以通过将类型和原因分别作为结构的一部分或为每个字段分配某些位来表示您的数据。
  • 即使你可以有一个枚举枚举,因为程序是由两台不同的机器运行的,相同的子枚举(例如 Type1Cause1)的值可能会被不同地实例化。不危险吗?

标签: c++ enums


【解决方案1】:

我什至不确定枚举的枚举是什么意思。但是 通常的处理方法是定义范围 单个枚举:

enum Errors
{
    type1 = 0x000,
    cause1,
    cause2,

    type2 = 0x100,
    cause3,
    cause4,
    ...
    causeMask = 0xFF,
    typeMask  = 0xFF00
};

或者简单地定义单独的枚举,用单独的词,并使用 unsigned(或unsigned short,或其他)和一点 铸造不同的原因。

无论采用什么解决方案,我都会将其封装在 一个类,这样客户端代码只需要处理errorType()errorCause()errorCause() 甚至可以是一个模板 错误类型值。 (但在某个地方,你需要明确 每个类型值的特化,因为编译器会 否则不知道如何将值映射到导致类型。)

【讨论】:

  • 对,以某种方式将类型嵌入到原因中是确保您不会混合错误类型和原因的唯一方法。这是最简单的方法。
【解决方案2】:

正如杰瑞所说,这是不可能的。解决这个问题的一种方法是有两个枚举。一个用于类别,一个用于子类别。

但是,正如 georgesl 所说,在协议中执行此操作可能很危险。您绝对应该明确定义枚举值:

struct Error
{
   enum Type {
      UNKNOWNTYPE = 0,
      TYPE1 = 1,
      TYPE2 = 2,
      TYPE3 = 3
   };
   enum Subtype {
      UNKNOWNSUBTYPE = 0,
      // subtype for error type 1
      CAUSE1 = 1001,
      CAUSE2 = 1002,
      CAUSE3 = 1003,
      // subtype for error type 2
      CAUSE4 = 2001,
      CAUSE5 = 2002
   };

   Type type;
   Subtype subtype;
};

int main()
{
   Error error;
   error.type = Error::TYPE1;
   error.subtype = Error::CAUSE1;
}

确保为将来的扩展明智地选择数字。

更新:使示例实际工作。

替代的、更安全的解决方案:

struct ErrorType
{
   enum type {
      UNKNOWNTYPE = 0,
      TYPE1 = 1,
      TYPE2 = 2,
      TYPE3 = 3
   };
};

struct ErrorSubtype
{
   enum type {
      UNKNOWNSUBTYPE = 0,
      // subtype for error type 1
      CAUSE1 = 1001,
      CAUSE2 = 1002,
      CAUSE3 = 1003,
      // subtype for error type 2
      CAUSE4 = 2001,
      CAUSE5 = 2002
   };
};

struct Error
{
   ErrorType::type type;
   ErrorSubtype::type subtype;
};

int main()
{
   Error error;
   error.type = ErrorType::TYPE1;
   error.subtype = ErrorSubtype::CAUSE1;
}

【讨论】:

  • 在这种情况下,我是否需要枚举类型,因为它已经在子类型中进行了编码?
  • 但是这种设计的问题是我可以加入错误类型和错误的子类型,即。我可以把 TYPE1 和 CAUSE4 结合起来,对吧?
  • 是的,就是这样。如果你想解耦,你可以创建三个结构体:Error、ErrorType 和 ErrorSubtype。然后让 Error 包含另外两个。
  • 我添加了一个更安全的解决方案。
  • 可以使用邪恶的宏来创建组合枚举值。这将防止使用错误的子类型。如果可以选择预处理器宏,我可以给出答案...
【解决方案3】:

我不建议这样做。更喜欢使用明确的错误类型,包含有关错误的信息(您可以添加字符串等)。这也不是很安全的类型。另请参阅 James 的回答。

但无论如何这里是邪恶的宏版本:

#define DECL_ERROR_TYPE(errorType, value) , errorType = value << 16
#define DECL_ERROR(errorType, cause, value) , errorType##_##cause = (errorType + value)

#define GET_ERROR_TYPE(error) (error & 0xFFFF0000)

enum Error
{
NoError = 0
DECL_ERROR_TYPE(Type1, 1)
DECL_ERROR(Type1, Cause1, 1)
DECL_ERROR(Type1, Cause2, 2)

DECL_ERROR_TYPE(Type2, 2)
DECL_ERROR(Type2, Cause1, 1)

DECL_ERROR_TYPE(Type3, 3)
DECL_ERROR(Type3, Cause1, 1)
DECL_ERROR(Type3, Cause2, 2)
};

这允许你像这样使用它:

Error err1 = Type1_Cause1;

if(Type1 == GET_ERROR_TYPE(err1))
    return 0; // Works

【讨论】:

    【解决方案4】:

    我无法忍受使用枚举。所以我有另一个使用显式类型的答案。 它不完整但显示了正确的方向,并且包含添加描述等可能的扩展。

    这是声明的代码:

    struct Error
    {
    public:
        struct ErrorType
        {
            int _code;
            ErrorType(int code) : _code(code << 16) {}
        };
    private:
        friend struct Errors;
        ErrorType _type;
        int _code;
    
        Error(ErrorType type, int causeCode)
            : _type(type), _code(causeCode)
        {
        }
    
        static std::map<int, Error> _errors;
    public:
        Error() : _type(-1), _code(-1) {}
        static Error FromCode(int code) { return _errors[code]; }
    
        bool IsOfType(const ErrorType& type )
        {
            return _type._code == type._code;
        }
    
        operator int()
        {
            return _code | _type._code;
        }
    
        bool operator == (Error const& other) const
        {
            return _code == other._code && _type._code == other._type._code;
        }
    
        bool operator != (Error const& other) const
        {
            return _code != other._code || _type._code != other._type._code;;
        }
    };
    
    std::map<int, Error> Error::_errors;
    
    struct Errors
    {
    #define BEGIN_TYPE(type, code) struct type : Error::ErrorType { type() : ErrorType(code) {} typedef Errors::##type CurrentType;
    #define CAUSE(cause, code) struct cause : Error { cause() : Error(CurrentType(),code) { Error::_errors[*this] = *this; } };
    #define END_TYPE() };
    
        // first type is coded manually to show what the macros do...
        struct Type1 : Error::ErrorType
        {
            Type1() : ErrorType(1) { }
            typedef Errors::Type1 CurrentType;
    
            struct Cause1 : Error
            {
                Cause1() : Error(CurrentType(),1) { Error::_errors[*this] = *this; }
            };
    
            struct Cause2 : Error
            {
                Cause2() : Error(CurrentType(),2) { Error::_errors[*this] = *this; }
            };
        };
    
        BEGIN_TYPE(Type2, 2)    
        CAUSE(Cause1, 1)
        CAUSE(Cause2, 2)
        END_TYPE()
    };
    

    以下是一些示例用法:

    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        Error err = Errors::Type1::Cause1();
    
        Q_ASSERT( err.IsOfType(Errors::Type1()) );
        Q_ASSERT( Errors::Type1::Cause1() == Errors::Type1::Cause1() );
        Q_ASSERT( Errors::Type1::Cause1() != Errors::Type2::Cause1() );
    
        int code = err;
        qDebug() << code;
        Q_ASSERT( Error::FromCode(code) == Errors::Type1::Cause1() );
        Q_ASSERT( Error::FromCode(code) != Errors::Type2::Cause1() );
        Q_ASSERT( Error::FromCode(code).IsOfType(Errors::Type1()) );
    
        return a.exec();
    }
    

    这不是一个完美的解决方案,但它显示了如何以更明确的方式处理这个问题。可以做很多改进...

    【讨论】:

      猜你喜欢
      • 2010-11-26
      • 1970-01-01
      • 2021-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-04
      相关资源
      最近更新 更多