2012-05-24 124 views
0

我想定義一個ICMP header作爲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 

但這樣做它是這樣的讓我覺得我只是搞亂周圍,使事情太複雜..我想這是一個更普遍的問題的具體例子:如何設置類型和子類型的系統?有什麼建議麼?

PS:

示例代碼:

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

張貼在外部網站上的代碼在這裏不贊成。我已將它移到你的問題中。 –

回答

1

我不認爲你可以在編譯時靜態地做到這一點,因爲你改變在運行時ICMPType

我建議:

  1. 做一個枚舉爲每個要代表code範圍。
  2. 爲每種類型創建一個容器(即每個類型特有的多個ICMPHeader類型,並在那裏丟失類型變量)。
  3. 創建一個需要原始ICMP頭的工廠,並使用相應的ICMPType enum生成一個專用類型。

這應該是一個非常靈活的方法,但根據類型簡單地轉換代碼的價值可能會足夠和更容易處理。

在你的例子中,你只是回到一個int,儘管哪一個你剝奪了一切你想要實現..?

編輯 - 如果您的所有容器都從一個公共基類繼承,那麼您可以給出一個通用的GetDescription()方法,然後子方可以填充該方法。抽象的細節就像一個很好的乾淨的設計...

+0

你說得對,在編譯時無法知道子類型,因此必須有一些運行時邏輯從ICMPType轉到ICMPCode。我認爲(2)和(3)是有趣的想法,我會稍微玩一下。 順便說一句,我在示例代碼中強制轉換爲int以打印數值,而不是字符。 – StackedCrooked