2013-03-15 115 views
14

是否有可能枚举的枚举在C++中。 我必须有这样的:是否有可能在enum中枚举枚举?

错误类型:

  • 的Type1
  • 2型
  • 的Type3

类型1:

  • 原因1
  • 原因2

类型2:

  • cause3
  • cause4

的Type3:

  • cause5
  • cause6

这些都是整数值。它们应该被用在通信协议栈中。在接收端,接收器必须根据接收到的值来解码错误的类型和原因。如果枚举不能使用,那么最好的方法是什么?

+10

对不起,但答案是否定的 - 你需要找到一种不同的方式来做事情。一种典型的方法是在数字中的某些高位中编码该类型,并且在一些低位中(例如,16位值,每个8位)导致该类型。 – 2013-03-15 08:32:36

+0

枚举的枚举是不可能的,但是可以通过将类型和原因分别作为结构的一部分或为每个字段分配特定位来表示数据。 – Tuxdude 2013-03-15 08:35:02

+1

即使您可以拥有enum枚举,因为程序由两个不同的机器运行,相同子枚举的值(例如Type1Cause1)可能会以不同方式实例化。这不危险吗? – lucasg 2013-03-15 08:38:46

回答

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; 
} 
+0

在这种情况下,我是否需要枚举类型,因为它已经在子类型中编码了? – sajas 2013-03-15 09:00:22

+0

我更新了我的答案,使其实际工作。 – Arne 2013-03-15 09:03:07

+0

但这个设计的问题是,我可以加入错误类型与错误的子类型,即。我可以将TYPE1与CAUSE4耦合,对吧? – sajas 2013-03-15 09:06:01

7

我甚至不知道什么枚举的枚举意味着什么。但处理这个 通常的方法是要么在 定义范围单一枚举:

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

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

或者简单地定义单独的枚举,在不同的话,使用 unsigned(或unsigned short,或什么都)和有点为 铸造为不同的原因。

无论采用的解决办法,我想将其封装在 一类,以便客户端代码只需要处理errorType()errorCause(); errorCause()甚至可能是 错误类型值的模板。 (但某处,每个类型值需要明确的 专业化,因为编译器将不会知道如何映射值以导致类型。)

+0

正确的,以某种方式将类型嵌入到原因中是确保不混合错误类型和原因的唯一方法。这是做这件事最简单的方法。 – 2013-03-15 09:50:43

3

我不会推荐这样做。倾向于使用明确的错误类型,包含有关错误的信息(您可以添加字符串等)。这也不是非常安全的。另见詹姆斯的回答。

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

#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 
0

我只是无法忍受使用枚举。所以我有另一个使用显式类型的答案。 它是不完整的,但显示了正确的方向,并含有添加的说明等

Here's报关代码的可能延长:

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(); 
} 

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