2012-06-13 5 views
39

ただ1つではなく、ある範囲の値に基づいてテンプレートの特殊化を行う方法はありますか?私は次のコードは有効なC + +コードではないが、私は何をしたいのかを示しています。私は8ビットマシン用のコードを書いているので、intとcharを使う速度に違いがあります。整数値の範囲に対してC++テンプレートを特殊化するにはどうすればよいですか?

template<unsigned SIZE> 
class circular_buffer { 
    unsigned char buffer[SIZE]; 
    unsigned int head; // index 
    unsigned int tail; // index 
}; 

template<unsigned SIZE <= 256> 
class circular_buffer { 
    unsigned char buffer[SIZE]; 
    unsigned char head; // index 
    unsigned char tail; // index 
}; 

答えて

45

を:

#include <type_traits> 

template<unsigned SIZE> 
class circular_buffer { 

    typedef typename 
     std::conditional< SIZE < 256, 
          unsigned char, 
          unsigned int 
         >::type 
     index_type; 

    unsigned char buffer[SIZE]; 
    index_type head; 
    index_type tail; 
}; 

コンパイラがまだC++ 11のこの部分をサポートしていない場合は、中に同等がありますboost libraries.

もう一度、あなたのロールするのは簡単です自身(クレジットはKerrekSBに行く):

template <bool, typename T, typename F> 
struct conditional { 
    typedef T type; 
}; 

template <typename T, typename F> // partial specialization on first argument 
struct conditional<false, T, F> { 
    typedef F type; 
}; 
+1

私はこれが便利だと言っています。 – chris

+6

'std :: conditional'のような特性は自分自身を書くのは簡単なことではないので、本当にライブラリを必要としないのであれば、本当に必要はありません:' template struct conditional {typedef T type; };テンプレート<タイプ名T、タイプ名U>構造体 {typedef Uタイプ; }; ' –

+0

乾杯@ KerrekSB、私は答えに加えました。 – jrok

33

余分不履行boolパラメータを使用しますstd::conditionalを試してみてください

// primary template handles false 
template<unsigned SIZE, bool IsSmall = SIZE <= 256> 
class circular_buffer { 
    unsigned char buffer[SIZE]; 
    unsigned int head; // index 
    unsigned int tail; // index 
}; 

// specialization for true 
template<unsigned SIZE> 
class circular_buffer<SIZE, true> { 
    unsigned char buffer[SIZE]; 
    unsigned char head; // index 
    unsigned char tail; // index 
}; 
+0

私は幸せになるだろう'IsSmall = SIZE <= 256'がどこかで括弧をつけていた場合 –

+0

@MooingDuck this? 'IsSmall =(SIZE <= 256)' –

+3

@MooingDuckは必要ありません。 '<'はデフォルトより小さい。そのため、 'テンプレート'の曖昧さがあります。混乱して '>'はデフォルトでは密接なテンプレートであり、そのためには括弧が必要です。 C++は素晴らしいですね。 –

7

別の可能なオプション:

template <unsigned SIZE> 
struct offset_size { 
    typedef typename offset_size<SIZE - 1>::type type; 
}; 

template <> 
struct offset_size<0> { 
    typedef unsigned char type; 
}; 

template <> 
struct offset_size<257> { 
    typedef unsigned int type; 
}; 

template<unsigned SIZE> 
class circular_buffer { 
    unsigned char buffer[SIZE]; 
    typename offset_size<SIZE>::type head; // index 
    typename offset_size<SIZE>::type tail; // index 
}; 

Ideone example)私はどのように対処する厄介なタイプでは、私は少しシンプルな何かを提案することができ嫌い

+7

あなたはそのようなサディストです、それはとても残酷です。コンパイラ。 'offset_size 'をコンパイルしようとすると、コンパイラは数十億のテンプレートクラスをインスタンス化する必要があります! – valdo

+0

実際、この手法に注意しないと、 'エラー:テンプレートのインスタンス化の深さが最大___を超えます '(デフォルトではgccでは500)のトリガーとなります。 – cdhowie

0

constexprを活用してください。この亜種は、様々なタイプが必要とされていない場合に異なる動作を可能にし、範囲内に収まるようにする必要性に対処し、価値のない片側だけ:触発され

template<bool> struct If; 

constexpr bool InClosedRange(std::size_t Value, std::size_t Lower, std::size_t Upper) 
{ 
    return (Lower <= Value) && (Value <= Upper); 
} 

// Usage: 
template<size_t Width, If<true>> 
class Foo; 

template<size_t Width, If<InClosedRange(Width, 1, 41)>> 
class Foo { /* ... */ }; 

template<size_t Width, If<InClosedRange(Width, 42, 142)>> 
class Foo { /* ... */ }; 

https://stackoverflow.com/a/9516959/929315

関連する問題