2017-09-13 20 views
1

私には、テンプレートパラメータNを持つクラスがあります。C++配列の種類はテンプレートの種類によって異なります

template<unsigned int N> 
class test { 
} 

は今、私はNビットを保持するために可能な限り小さい整数型でstd::vectorを持っていると思います。

など。

class test<8> { 
    std::vector<uint8_t> data; 
} 

class test<9> { 
    std::vector<uint16_t> data; 
} 

class test<10> { 
    std::vector<uint16_t> data; 
} 
... 

N=64N=1のためにこれを行うに任意のより良い方法はありますか?

+0

このような 'vector'sのユースケースは何ですか? ['std :: bitset'](http://en.cppreference.com/w/cpp/utility/bitset)はあなたの問題を解決しますか? –

+0

結果のベクトルをソートしたいので、ビットセットは実現できません。 – eclipse

+0

さらにいくつかの文脈を与える:これは、4文字のアルファベット(ゲノム)から固定長の何十億もの文字列を表現するクラスです。 Nは文字数、最大値は32です.4のアルファベットのうち32文字は64ビットで表現できます。したがってベクターは基本的に小さなゲノムサンプルがたくさんあり、それらのサンプルのサイズは一般的でなければなりません。 – eclipse

答えて

3

条件付きではどうですか?

#include <vector> 
#include <cstdint> 
#include <iostream> 
#include <type_traits> 

template <std::size_t N> 
struct foo 
{ 
    static_assert(N < 65U, "foo 64 limit"); 

    using vType = typename std::conditional< 
     (N < 9U), std::uint8_t, 
     typename std::conditional< (N < 17U), std::uint16_t, 
      typename std::conditional< (N < 33U), std::uint32_t, std::uint64_t 
    >::type>::type>::type; 

    std::vector<vType> data; 
}; 

int main() 
{ 
    static_assert(1U == sizeof(foo<1>::vType), "!"); 
    static_assert(1U == sizeof(foo<8>::vType), "!"); 
    static_assert(2U == sizeof(foo<9>::vType), "!"); 
    static_assert(2U == sizeof(foo<16>::vType), "!"); 
    static_assert(4U == sizeof(foo<17>::vType), "!"); 
    static_assert(4U == sizeof(foo<32>::vType), "!"); 
    static_assert(8U == sizeof(foo<33>::vType), "!"); 
    static_assert(8U == sizeof(foo<64>::vType), "!"); 

    // foo<65> f65; compilation error 
} 

それとも、もっとエレガントな方法(私見)、あなたはリストの最初の有用なタイプを選択します(以下の例ではselectTypeByDim、)タイプの特性を定義することができますに

#include <tuple> 
#include <vector> 
#include <cstdint> 
#include <climits> 
#include <type_traits> 

template <std::size_t N, typename T, 
    bool = (N <= sizeof(typename std::tuple_element<0U, T>::type)*CHAR_BIT)> 
struct stbdH; 

template <std::size_t N, typename T0, typename ... Ts> 
struct stbdH<N, std::tuple<T0, Ts...>, true> 
{ using type = T0; }; 

template <std::size_t N, typename T0, typename ... Ts> 
struct stbdH<N, std::tuple<T0, Ts...>, false> 
{ using type = typename stbdH<N, std::tuple<Ts...>>::type; }; 

template <std::size_t N, typename ... Ts> 
struct selectTypeByDim : stbdH<N, std::tuple<Ts...>> 
{ }; 

template <std::size_t N> 
struct foo 
{ 
    static_assert(N < 65U, "foo 64 limit"); 

    using vType = typename selectTypeByDim<N, 
     std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t>::type; 

    std::vector<vType> data; 
}; 

int main() 
{ 
    static_assert(1U == sizeof(foo<1U>::vType), "!"); 
    static_assert(1U == sizeof(foo<CHAR_BIT>::vType), "!"); 
    static_assert(2U == sizeof(foo<CHAR_BIT+1U>::vType), "!"); 
    static_assert(2U == sizeof(foo<(CHAR_BIT<<1)>::vType), "!"); 
    static_assert(4U == sizeof(foo<(CHAR_BIT<<1)+1U>::vType), "!"); 
    static_assert(4U == sizeof(foo<(CHAR_BIT<<2)>::vType), "!"); 
    static_assert(8U == sizeof(foo<(CHAR_BIT<<2)+1U>::vType), "!"); 
    static_assert(8U == sizeof(foo<(CHAR_BIT<<3)>::vType), "!"); 

    //foo<(CHAR_BIT<<3)+1U> f65; compilation error 
} 
+0

これは完璧なおかげで、とても美しいです。 – eclipse

1

に基づきますあなたの質問へのコメントは、実際に組み込み型を必要としません。任意のコピー可能な移動可能オブジェクトをベクトルに入れることができます。

あなたがデータをどうしたいすべてのソートそれであれば(あなたは奇妙なシステム上で実行している場合やstd::array<std::byte, (2*N+CHAR_BIT-1)/CHAR_BIT>)、私は、ソートのカスタムComparestd::bitset<2*N>またはstd::array<std::byte, (2*N+7)/8>のいずれかをお勧めします。他の用途がある場合は(おそらくそうですが)、そのうちの1つを基にしたカスタムクラスをお勧めします。特定のベースを取得するなどの機能を追加できます。ほとんどのシステムで

N 32または64(実装に依存する)のいずれかの倍数であり、それは保証されていない場合、std::bitsetはオーバーヘッドを持たないであろう。バイト配列には、C++で一般的に必要とされる以上のオーバヘッドはありません。これらの両方を必要に応じて64ビットを超えて拡張することができ、バイト配列のサイズは2の累乗にならないため、バイト配列は整数型を使用するよりもスペースのオーバーヘッドが最小になります。これらのいずれかの上にカスタムクラスを追加しても、オーバーヘッドはまったくありません。

(あなたがC++ 14またはあなたの代わりにbytecharまたはuint8_tを使用することができます下に使用している場合は、byteはあなたが望むものに近いですが、C++ 17でのみ利用可能ですあなたはC +を使用している場合を。 +14が今でも切り替える可能性があります。using byte = uint8_tをあなたのコードのどこかに入れてからアップグレードすることをお勧めします)

+0

私は実際にバイト配列を持つソリューションを使用しました。しかし、私は他の選択肢を考えさせてくれる一つのことが間違っていると思う。 'std :: array という1つのフィールドしか持たないクラスがあると、そのクラスのオブジェクトはどのようにベクトルの中にレイアウトされていますか?私は今日、「新しいプレースメント」について読んでいます。しかし、私はこの場合どのように動作するかを100%確信していません。あなたはそれがオーバーヘッドを追加しないと言う、どのようにそう? – eclipse

+1

ベクトルには、配列のように連続してレイアウトされた複数のオブジェクトが連続して配置されていますが、実行時に作成されます。クラスはメンバーのそれぞれとまったく同じように配置されています。おそらく、メンバー同士の間にいくつかのパディングがあります。それは1つのデータメンバしか持たないので、それを使うだけではアラインメントの追加要件はなく、そのデータメンバはアラインメント要件をもたない 'byte'であるため、パディングはありません。 –

+0

Hm大丈夫です。このように 'std :: byte []'ではどのように動作するのでしょうか?しかし、 'std :: array'には複数のメンバーがあります。 – eclipse

関連する問題