Reputation: 1780
Is there a way to have a template specialization based on a range of values instead of just one? I know the following code is not valid C++ code but it shows what I would like to do. I'm writing code for a 8-bit machine, so there is a difference in speed for using ints and chars.
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
};
Upvotes: 45
Views: 4507
Reputation: 549
I hate how messy dealing with types can be so I propose something a bit simpler, leveraging constexpr
. This variant allows for differing behavior when a varying type is not required and addresses the need to fit within a range and not just one side of a value:
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 { /* ... */ };
Inspired by: https://stackoverflow.com/a/9516959/929315
Upvotes: 0
Reputation: 55395
Try std::conditional:
#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;
};
If your compiler doesn't yet support this part of C++11, there's equivalent in boost libraries.
Then again, it's easy to roll your own (credit goes to 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;
};
Upvotes: 51
Reputation: 169028
Another possible option:
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
};
Upvotes: 7
Reputation: 234504
Use an extra defaulted bool
parameter:
// 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
};
Upvotes: 36