我想将ICMP 标头定义为 pod 类型:
struct ICMPHeader
{
uint8_t Type; // ICMP type
uint8_t Code; // Subtype, value is dependent on ICMP type.
uint16_t Checksum; // Error checking data. See RFC 1071
uint32_t RestOfHeader; // Varies based on ICMP type and code.
};
对于该ICMPType
领域,我可以使用强类型枚举来使它更好一点:
enum class ICMPType : uint8_t
{
EchoReply = 0,
Reserved1 = 1,
Reserved2 = 2,
DestinationUnreachable = 3,
SourceQuench = 4
// etc...
};
struct ICMPHeader
{
ICMPType Type; // ICMP type
uint8_t Code; // Subtype, value is dependent on ICMP type.
uint16_t Checksum; // Error checking data. See RFC 1071
uint32_t RestOfHeader; // Varies based on ICMP type and code.
};
现在,我自然也想将Code
字段指定为枚举。如果我可以使用模板专业化语法会很好,但快速测试表明它不起作用:
// Compiler error
template<ICMPType>
enum class ICMPCode;
template<>
enum class ICMPCode<ICMPType::DestinationUnreachable>
{
DestinationNetworkUnreachable = 0,
DestinationHostUnreachable = 1,
DestinationProtocolUnreachable = 2
};
一种选择是将它们包装在结构中:
// Meaning of ICMP code is dependent on ICMP type.
template<ICMPType>
struct ICMPCode;
// Subcodes for DestinationUnreachable
template<> struct ICMPCode<ICMPType::DestinationUnreachable>
{
enum class Code : uint8_t
{
DestinationNetworkUnreachable = 0,
DestinationHostUnreachable = 1,
DestinationProtocolUnreachable = 2
// etc...
};
};
// Access: ICMPCode<ICMPType::DestinationUnreachable>::Code::DestinationHostUnreachable
但这样做让我觉得我只是在胡闹,让事情变得太复杂..
我想这是一个更普遍问题的具体示例:如何设置类型和子类型系统?有什么建议么?
附言:
示例代码:
#include <iostream>
// Trying to model ICMP types and codes with strongly typed enums
// See also http://en.wikipedia.org/wiki/Internet_Control_Message_Protocol#Header
enum class ICMPType : uint8_t
{
EchoReply = 0,
Reserved1 = 1,
Reserved2 = 2,
DestinationUnreachable = 3,
SourceQuench = 4
// etc...
};
// Meaning of ICMP code is dependent on ICMP type.
template<ICMPType>
struct ICMPCode;
// Subcodes for DestinationUnreachable
template<> struct ICMPCode<ICMPType::DestinationUnreachable>
{
enum class Code : uint8_t
{
DestinationNetworkUnreachable = 0,
DestinationHostUnreachable = 1,
DestinationProtocolUnreachable = 2
// etc...
};
};
ICMPCode<ICMPType::DestinationUnreachable>::Code GetReasonWhyDestinationIsUnreachable()
{
return ICMPCode<ICMPType::DestinationUnreachable>::Code::DestinationHostUnreachable;
}
int main()
{
std::cout << static_cast<int>(GetReasonWhyDestinationIsUnreachable()) << std::endl;
}