packed_bits
可変個引数テンプレートと を使用してクラスを実装しようとしていstd::bitset
ます。
特に、すべてのパックされたビットを含むget
メンバーのサブセットへの参照を返す関数を作成する際に問題が発生しています。関数はform_bits
に似ている必要があります。std::get
std::tuple
のサブセットを操作できるように、参照オーバーレイとして機能する必要がありpacked_bits
ます。
例えば、
using my_bits = packed_bits<8,16,4>;
my_bits b;
std::bitset< 8 >& s0 = get<0>( b );
std::bitset< 16 >& s1 = get<1>( b );
std::bitset< 4 >& s2 = get<2>( b );
アップデート
以下は、以下の Yakk の推奨事項に従って書き直されたコードです。私は彼の最後の段落のポイントで立ち往生しています:個々の参照を 1 つのビットセットのような参照に結合する方法がわかりません。その最後の部分に今考えている/取り組んでいます。
更新 2
bit_slice<>
さて、私の新しいアプローチは、大部分の作業を任せることです。
- それは短命であることを意味します
std::bitset<length>
一時的なバッファとして機能し、パブリックにサブクラス化します- 構築時に、それはからコピーされます
packed_bits<>& m_parent;
- 破壊時に、それはに書き込みます
m_parent
- による参照に加えて、
m_parent
オフセット、長さも知っている必要があります get<>
を取り、参照ではなく値packet_bits<>
を返すフリー関数になりますbit_slice<>
bitset<>
このアプローチにはさまざまな欠点があります。
bit_slice<>
構築と破棄のみを更新するため、エイリアシングの問題を回避するために比較的短命である必要があります- コーディング中に複数の重複参照を避ける必要があります (スレッド化されているかどうかに関係なく)。
- 子クラスのインスタンスがあるときに基本クラスへのポインターを保持しようとすると、スライスが発生しやすくなります。
しかし、これで私のニーズには十分だと思います。完成したコードを投稿します。
更新 3
コンパイラと戦った後、基本的なバージョンが機能していると思います。残念ながら、フリーフローティング::get()
を適切にコンパイルすることができませんでした: BROKEN
スポットを示しています。そうでなければ、私はそれが働いていると思います。
Yakk の提案に感謝します。以下のコードは、彼のコメントに基づいて約 90% 以上です。
更新 4
フリーフローティング::get()
固定。
更新 5
Yakk が提案したように、コピーを削除しました。 bit_slice<>
読みget_value()
続けて書きますset_value()
。いずれにせよ、おそらく私の呼び出しの 90% 以上はこれらのインターフェイスを介して行われるため、サブクラス化/コピーする必要はありません。
もう汚れません。
コード
#include <cassert>
#include <bitset>
#include <iostream>
// ----------------------------------------------------------------------------
template<unsigned... Args>
struct Add { enum { val = 0 }; };
template<unsigned I,unsigned... Args>
struct Add<I,Args...> { enum { val = I + Add<Args...>::val }; };
template<int IDX,unsigned... Args>
struct Offset { enum { val = 0 }; };
template<int IDX,unsigned I,unsigned... Args>
struct Offset<IDX,I,Args...> {
enum {
val = IDX>0 ? I + Offset<IDX-1,Args...>::val : Offset<IDX-1,Args...>::val
};
};
template<int IDX,unsigned... Args>
struct Length { enum { val = 0 }; };
template<int IDX,unsigned I,unsigned... Args>
struct Length<IDX,I,Args...> {
enum {
val = IDX==0 ? I : Length<IDX-1,Args...>::val
};
};
// ----------------------------------------------------------------------------
template<unsigned... N_Bits>
struct seq
{
static const unsigned total_bits = Add<N_Bits...>::val;
static const unsigned size = sizeof...( N_Bits );
template<int IDX>
struct offset
{
enum { val = Offset<IDX,N_Bits...>::val };
};
template<int IDX>
struct length
{
enum { val = Length<IDX,N_Bits...>::val };
};
};
// ----------------------------------------------------------------------------
template<unsigned offset,unsigned length,typename PACKED_BITS>
struct bit_slice
{
PACKED_BITS& m_parent;
bit_slice( PACKED_BITS& t ) :
m_parent( t )
{
}
~bit_slice()
{
}
bit_slice( bit_slice const& rhs ) :
m_parent( rhs.m_parent )
{ }
bit_slice& operator=( bit_slice const& rhs ) = delete;
template<typename U_TYPE>
void set_value( U_TYPE u )
{
for ( unsigned i=0; i<length; ++i )
{
m_parent[offset+i] = u&1;
u >>= 1;
}
}
template<typename U_TYPE>
U_TYPE get_value() const
{
U_TYPE x = 0;
for ( int i=length-1; i>=0; --i )
{
if ( m_parent[offset+i] )
++x;
if ( i!=0 )
x <<= 1;
}
return x;
}
};
template<typename SEQ>
struct packed_bits :
public std::bitset< SEQ::total_bits >
{
using bs_type = std::bitset< SEQ::total_bits >;
using reference = typename bs_type::reference;
template<int IDX> using offset = typename SEQ::template offset<IDX>;
template<int IDX> using length = typename SEQ::template length<IDX>;
template<int IDX> using slice_type =
bit_slice<offset<IDX>::val,length<IDX>::val,packed_bits>;
template<int IDX>
slice_type<IDX> get()
{
return slice_type<IDX>( *this );
}
};
template<int IDX,typename T>
typename T::template slice_type<IDX>
get( T& t )
{
return t.get<IDX>();
};
// ----------------------------------------------------------------------------
int main( int argc, char* argv[] )
{
using my_seq = seq<8,16,4,8,4>;
using my_bits = packed_bits<my_seq>;
using my_slice = bit_slice<8,16,my_bits>;
using slice_1 =
bit_slice<my_bits::offset<1>::val,my_bits::length<1>::val,my_bits>;
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<0>::val==0 );
assert( my_seq::offset<1>::val==8 );
assert( my_seq::offset<2>::val==24 );
assert( my_seq::offset<3>::val==28 );
assert( my_seq::offset<4>::val==36 );
assert( my_seq::length<0>::val==8 );
assert( my_seq::length<1>::val==16 );
assert( my_seq::length<2>::val==4 );
assert( my_seq::length<3>::val==8 );
assert( my_seq::length<4>::val==4 );
{
auto s2 = b.get<2>();
}
{
auto s2 = ::get<2>( b );
s2.set_value( 25 ); // 25==11001, but only 4 bits, so we take 1001
assert( s2.get_value<unsigned>()==9 );
}
return 0;
}