title: How to access a slice of packed_bits<> as a std::bitset<>?
body: <p>I am attempting to implement a <code>packed_bits</code> class using variadic templates and <code>std::bitset</code>.</p>
  
  <p>In particular, I am running into problems writing a <code>get</code> function which returns a reference to a subset of the member <code>m_bits</code> which contains all the packed bits.  The function should be analogous to <code>std::get</code> for <code>std::tuple</code>.</p>
  
  <p>It should act as an <em>reference overlay</em> so I can manipulate a subset of <code>packed_bits</code>.</p>
  
  <p>For instance,</p>
  
  <pre><code>using my_bits = packed_bits&lt;8,16,4&gt;;
  my_bits b;
  std::bitset&lt;  8 &gt;&amp; s0 = get&lt;0&gt;( b );
  std::bitset&lt; 16 &gt;&amp; s1 = get&lt;1&gt;( b );
  std::bitset&lt;  4 &gt;&amp; s2 = get&lt;2&gt;( b );
  </code></pre>
  
  <p><strong>UPDATE</strong></p>
  
  <p>Below is the code that has been rewritten according to <a href="https://stackoverflow.com/a/14906694/975129">Yakk's recommendations below</a>.  I am stuck at the point of his last paragraph: not sure how to <em>glue together</em> the individual references into one <em>bitset-like</em> reference.  Thinking/working on that last part now.</p>
  
  <p><strong>UPDATE 2</strong></p>
  
  <p>Okay, my new approach is going to be to let <code>bit_slice&lt;&gt;</code> do the bulk of the work:</p>
  
  <ul>
  <li>it is meant to be short-lived</li>
  <li>it will publicly subclass <code>std::bitset&lt;length&gt;</code>, acting as a temporary buffer</li>
  <li>on construction, it will copy from <code>packed_bits&lt;&gt;&amp; m_parent;</code></li>
  <li>on destruction, it will write to <code>m_parent</code> </li>
  <li>in addition to the reference via <code>m_parent</code>, it must also know offset, length</li>
  <li><code>get&lt;&gt;</code> will become a free-function which takes a <code>packet_bits&lt;&gt;</code> and returns a <code>bit_slice&lt;&gt;</code> by value instead of <code>bitset&lt;&gt;</code> by reference</li>
  </ul>
  
  <p>There are various short-comings to this approach:</p>
  
  <ul>
  <li><code>bit_slice&lt;&gt;</code> has to be relatively short-lived to avoid aliasing issues, since we only update on construction and destruction</li>
  <li>we must avoid multiple overlapping references while coding (whether threaded or not)</li>
  <li>we will be prone to slicing if we attempt to hold a pointer to the base class when we have an instance of the child class</li>
  </ul>
  
  <p>but I think this will be sufficient for my needs.  I will post the finished code when it is complete.</p>
  
  <p><strong>UPDATE 3</strong></p>
  
  <p>After fighting with the compiler, I think I have a basic version working.  Unfortunately, I could not get the free-floating <code>::get()</code> to compile properly:  <code>BROKEN</code> shows the spot.  Otherwise, I think it's working.</p>
  
  <p><em>Many thanks to Yakk for his suggestions: the code below is about 90%+ based on his comments.</em></p>
  
  <p><strong>UPDATE 4</strong></p>
  
  <p>Free-floating <code>::get()</code> fixed.</p>
  
  <p><strong>UPDATE 5</strong></p>
  
  <p>As suggested by Yakk, I have eliminated the copy.  <code>bit_slice&lt;&gt;</code> will read on <code>get_value()</code> and write on <code>set_value()</code>.  Probably 90%+ of my calls will be through these interfaces anyways, so no need to subclass/copy.</p>
  
  <p>No more dirtiness.</p>
  
  <p><strong>CODE</strong></p>
  
  <pre><code>#include &lt;cassert&gt;
  #include &lt;bitset&gt;
  #include &lt;iostream&gt;
  
  // ----------------------------------------------------------------------------
  
  template&lt;unsigned... Args&gt;
  struct Add { enum { val = 0 }; };
  
  template&lt;unsigned I,unsigned... Args&gt;
  struct Add&lt;I,Args...&gt; { enum { val = I + Add&lt;Args...&gt;::val }; };
  
  template&lt;int IDX,unsigned... Args&gt;
  struct Offset { enum { val = 0 }; };
  
  template&lt;int IDX,unsigned I,unsigned... Args&gt;
  struct Offset&lt;IDX,I,Args...&gt; { 
      enum { 
          val = IDX&gt;0 ? I + Offset&lt;IDX-1,Args...&gt;::val : Offset&lt;IDX-1,Args...&gt;::val 
      }; 
  };
  
  template&lt;int IDX,unsigned... Args&gt;
  struct Length { enum { val = 0 }; };
  
  template&lt;int IDX,unsigned I,unsigned... Args&gt;
  struct Length&lt;IDX,I,Args...&gt; { 
      enum { 
          val = IDX==0 ? I : Length&lt;IDX-1,Args...&gt;::val 
      }; 
  };
  
  // ----------------------------------------------------------------------------
  
  template&lt;unsigned... N_Bits&gt;
  struct seq
  {
      static const unsigned total_bits = Add&lt;N_Bits...&gt;::val;
      static const unsigned size       = sizeof...( N_Bits );
  
      template&lt;int IDX&gt;
      struct offset
      {
          enum { val = Offset&lt;IDX,N_Bits...&gt;::val };
      };
  
      template&lt;int IDX&gt;
      struct length
      {
          enum { val = Length&lt;IDX,N_Bits...&gt;::val };
      };
  };
  
  // ----------------------------------------------------------------------------
  
  template&lt;unsigned offset,unsigned length,typename PACKED_BITS&gt;
  struct bit_slice
  {
      PACKED_BITS&amp; m_parent;
  
      bit_slice( PACKED_BITS&amp; t ) :
          m_parent( t )
      { 
      }
  
      ~bit_slice()
      {
      }
  
      bit_slice( bit_slice const&amp; rhs ) :
          m_parent( rhs.m_parent )
      { }
  
      bit_slice&amp; operator=( bit_slice const&amp; rhs ) = delete;
  
      template&lt;typename U_TYPE&gt;
      void set_value( U_TYPE u )
      {
          for ( unsigned i=0; i&lt;length; ++i )
          {
              m_parent[offset+i] = u&amp;1;
              u &gt;&gt;= 1;
          }
      }
  
      template&lt;typename U_TYPE&gt;
      U_TYPE get_value() const
      {
          U_TYPE x = 0;
          for ( int i=length-1; i&gt;=0; --i )
          {
              if ( m_parent[offset+i] )
                  ++x;
              if ( i!=0 )
                  x &lt;&lt;= 1;
          }
          return x;
      }
  };
  
  template&lt;typename SEQ&gt;
  struct packed_bits :
      public std::bitset&lt; SEQ::total_bits &gt;
  {  
      using bs_type   = std::bitset&lt; SEQ::total_bits &gt;;
      using reference = typename bs_type::reference;
  
      template&lt;int IDX&gt; using offset = typename SEQ::template offset&lt;IDX&gt;;
      template&lt;int IDX&gt; using length = typename SEQ::template length&lt;IDX&gt;;
      template&lt;int IDX&gt; using slice_type = 
          bit_slice&lt;offset&lt;IDX&gt;::val,length&lt;IDX&gt;::val,packed_bits&gt;;
  
      template&lt;int IDX&gt;
      slice_type&lt;IDX&gt; get()
      {
          return slice_type&lt;IDX&gt;( *this );
      }
  };
  
  template&lt;int IDX,typename T&gt;
  typename T::template slice_type&lt;IDX&gt;
  get( T&amp; t )
  {
      return t.get&lt;IDX&gt;();
  };
  
  // ----------------------------------------------------------------------------
  
  int main( int argc, char* argv[] )
  {
      using my_seq   = seq&lt;8,16,4,8,4&gt;;
      using my_bits  = packed_bits&lt;my_seq&gt;;
      using my_slice = bit_slice&lt;8,16,my_bits&gt;;
      using slice_1  = 
          bit_slice&lt;my_bits::offset&lt;1&gt;::val,my_bits::length&lt;1&gt;::val,my_bits&gt;;
  
      my_bits        b;
      my_slice       s(  b );
      slice_1        s1( b );
  
      assert( sizeof( b )==8 );
      assert( my_seq::total_bits==40 );
      assert( my_seq::size==5 );
  
      assert( my_seq::offset&lt;0&gt;::val==0  );
      assert( my_seq::offset&lt;1&gt;::val==8  );
      assert( my_seq::offset&lt;2&gt;::val==24 );
      assert( my_seq::offset&lt;3&gt;::val==28 );
      assert( my_seq::offset&lt;4&gt;::val==36 );
  
      assert( my_seq::length&lt;0&gt;::val==8  );
      assert( my_seq::length&lt;1&gt;::val==16 );
      assert( my_seq::length&lt;2&gt;::val==4  );
      assert( my_seq::length&lt;3&gt;::val==8  );
      assert( my_seq::length&lt;4&gt;::val==4  );
  
      {
          auto s2 = b.get&lt;2&gt;();
      }
      {
          auto s2 = ::get&lt;2&gt;( b );
          s2.set_value( 25 );  // 25==11001, but only 4 bits, so we take 1001 
          assert( s2.get_value&lt;unsigned&gt;()==9 );
      }
  
      return 0;
  }
  </code></pre>