title: Generic switch statement to initialize derived types
body: <p>I'm creating a DNS name resolver. While parsing the returned packet I read the RR type then pass it through switch to initialize a derived type of class Record. Record types is a large enum type. I map the enum to a struct using template specialization.</p>
  
  <pre><code>template &lt; QueryType n &gt;
  struct Struct;
  
  template &lt;&gt; struct Struct&lt; DNS_Q_A &gt; { typedef A Type; };
  template &lt;&gt; struct Struct&lt; DNS_Q_CNAME &gt; { typedef CNAME Type; };
  
  template &lt; QueryType n &gt; struct Struct { typedef UNKNOWN Type; };
  </code></pre>
  
  <p>Currently I have 4 switch statements which all do a very similar thing. Namely call operator new, placement new, for both copy and move c'tors. This is a lot of code to maintain. I would like to have just 1 switch statement where I could pass in some type of object containing the function to perform, return type and n number of parameters.</p>
  
  <p>The switch statements are like this:</p>
  
  <pre><code>switch ( nType )
  {
  case DNS_Q_A:
      pInstance = new ( &amp;Container ) Struct&lt; DNS_Q_A &gt;::Type( dynamic_cast&lt; const Struct&lt; DNS_Q_A &gt;::Type&amp; &gt;( Other ) );
      break;
  case DNS_Q_CNAME:
      pInstance = new ( &amp;Container ) Struct&lt; DNS_Q_CNAME &gt;::Type( dynamic_cast&lt; const Struct&lt; DNS_Q_CNAME &gt;::Type&amp; &gt;( Other ) );
      break;
  }
  </code></pre>
  
  <p>As you can see, each case is identical other than the reliance on the struct type. This screams out 'template' to me but I can't figure out how to pass in an object.</p>
  
  <p>Am I limited to coding 4 switch's or is there a way? Please don't quote "Boost", this code has to be independent of any other libraries.</p>
  
  <p>Solution: (Thanks to Jan Hudec)</p>
  
  <pre><code>template&lt; template &lt; class &gt; class Action &gt;
  typename Action&lt; Struct&lt; DNS_Q_A &gt;::Type &gt;::result_type
      CreateRecord ( 
          unsigned n,
          typename Action&lt; Struct&lt; DNS_Q_A &gt;::Type &gt;::first_argument_type arg1,
          typename Action&lt; Struct&lt; DNS_Q_A &gt;::Type &gt;::second_argument_type arg2 )
  {
      typedef typename typename Action&lt; Struct&lt; DNS_Q_A &gt;::Type &gt;::result_type ReturnType;
      switch ( n )
      {
      case DNS_Q_A:       return static_cast&lt; ReturnType &gt;( Action&lt; Struct&lt; DNS_Q_A &gt;::Type &gt;()( arg1, arg2 ) );
      case DNS_Q_NS:      return static_cast&lt; ReturnType &gt;( Action&lt; Struct&lt; DNS_Q_NS &gt;::Type &gt;()( arg1, arg2 ) );
      /*...*/
      }
  }
  </code></pre>
  
  <p>with Action struct defined as:</p>
  
  <pre><code>template &lt; typename T &gt;
  struct Copy : std::binary_function&lt; storage_type&amp;, const Record&amp;, Record* &gt;
  {
      Record* operator() ( storage_type&amp; Storage, const Record&amp; Obj )
      {
          return new ( &amp;Storage ) T( dynamic_cast&lt; const T&amp; &gt;( Obj ) );
      }
  };
  template &lt; typename T &gt;
  struct Move : std::binary_function&lt; storage_type&amp;, Record&amp;&amp;, Record* &gt;
  {
      Record* operator() ( storage_type&amp; Storage, const Record&amp; Obj )
      {
          return new ( &amp;Storage ) T( dynamic_cast&lt; const T&amp; &gt;( std::move( Obj ) ) );
      }
  };
  </code></pre>
  
  <p>And Switch statements replaced with:</p>
  
  <pre><code>pInstance = CreateRecord&lt; Copy &gt;( nType, Container, Other );
  </code></pre>