Modeling types and subtypes with strongly typed enums?
<p>I want to define a <a href="http://en.wikipedia.org/wiki/Internet_Control_Message_Protocol#Header" rel="nofollow">ICMP header</a> as a pod type:</p>

<pre><code>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.
};
</code></pre>

<p>For the <code>ICMPType</code> field I can use strongly typed enums to make it a bit nicer:</p>

<pre><code>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></pre>

<p>Now, I naturally also want to specify the <code>Code</code> field as an enum. It would be nice if I could use template specialization syntax, but a quick test reveals that it doesn't work:</p>

<pre><code>// Compiler error
template&lt;ICMPType&gt;
enum class ICMPCode;    

template&lt;&gt;
enum class ICMPCode&lt;ICMPType::DestinationUnreachable&gt;
{
    DestinationNetworkUnreachable  = 0,
    DestinationHostUnreachable     = 1,
    DestinationProtocolUnreachable = 2
};
</code></pre>

<p>One option would be to wrap them in structs:</p>

<pre><code>// Meaning of ICMP code is dependent on ICMP type.
template&lt;ICMPType&gt;
struct ICMPCode;

// Subcodes for DestinationUnreachable
template&lt;&gt; struct ICMPCode&lt;ICMPType::DestinationUnreachable&gt;
{
    enum class Code : uint8_t
    {
        DestinationNetworkUnreachable  = 0,
        DestinationHostUnreachable     = 1,
        DestinationProtocolUnreachable = 2

        // etc...
    };
};

// Access: ICMPCode&lt;ICMPType::DestinationUnreachable&gt;::Code::DestinationHostUnreachable
</code></pre>

<p>But doing it like this makes me feel that I'm just messing around and making things too complex..</p>

<p>I guess this is a specific example of a more general question: How to setup a system of types and subtypes? Any suggestions?</p>

<p>Ps:</p>

<ul>
<li>See also: <a href="http://en.wikipedia.org/wiki/Internet_Control_Message_Protocol#Header" rel="nofollow">http://en.wikipedia.org/wiki/Internet_Control_Message_Protocol#Header</a></li>
</ul>

<p>Sample code:</p>

<pre><code>#include &lt;iostream&gt;

// 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&lt;ICMPType&gt;
struct ICMPCode;


// Subcodes for DestinationUnreachable
template&lt;&gt; struct ICMPCode&lt;ICMPType::DestinationUnreachable&gt;
{
    enum class Code : uint8_t
    {
        DestinationNetworkUnreachable  = 0,
        DestinationHostUnreachable     = 1,
        DestinationProtocolUnreachable = 2

        // etc...
    };
};


ICMPCode&lt;ICMPType::DestinationUnreachable&gt;::Code GetReasonWhyDestinationIsUnreachable()
{
    return ICMPCode&lt;ICMPType::DestinationUnreachable&gt;::Code::DestinationHostUnreachable;
}


int main()
{
    std::cout &lt;&lt; static_cast&lt;int&gt;(GetReasonWhyDestinationIsUnreachable()) &lt;&lt; std::endl;
}
</code></pre>
