0

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;
}
4

1 に答える 1

1

ICMPType実行時に変更するため、コンパイル時に静的にこれを行うことはできないと思います。

私は提案します:

  1. 表現する範囲ごとに列挙型を作成しcodeます。
  2. タイプごとにコンテナを作成します(つまり、ICMPHeader各タイプに固有の複数のタイプがあり、そこで型変数が失われます)。
  3. 元のICMPヘッダーを取得し、適切なICMPType列挙型を持つ特殊なタイプの1つを生成するファクトリを作成します。

これはかなり柔軟なアプローチであるはずですが、タイプに応じてコードの値をキャストするだけで十分であり、処理がはるかに簡単になります。

あなたの例では、intにキャストバックしますが、これにより、達成しようとしているすべてのものが削除されます。

編集-すべてのコンテナが共通の基本クラスから継承されている場合は、子が設定できる汎用のGetDescription()メソッドを指定できます。このように細部を抽象化すると、すっきりとしたデザインになります...

于 2012-05-24T13:30:33.667 に答える