ICMPヘッダーをポッドタイプとして定義したい:
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
};
1つのオプションは、それらを構造体でラップすることです。
// 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;
}