7

I wish to write a template structure foo such that foo<N>::value_type is the nearest sized integer (rounding up) to N. For example foo<32>::value_type => uint32_t, foo<33>::value_type => uint64_t and foo<72>::value_type => uint64_t.

To do this I need an elegant means of providing partial specializations of foo for a range of values, e.g, 1 <= N <= 8 to return uint8_t and so on and so fourth. Is there a means of accomplishing this without having to specialise everything from 0 to 64.

Freddie Witherden
  • 2,369
  • 1
  • 26
  • 41
  • There won't be a direct way (like Mark said), but maybe some clever template metaprogramming trick. Nice question, waiting to see the answers. – Christian Rau Oct 04 '11 at 17:29

3 Answers3

15
template<size_t N> struct select { typedef uint64_t result; };
template<> struct select<0> { typedef uint8_t result; };
template<> struct select<1> { typedef uint16_t result; };
template<> struct select<2> { typedef uint32_t result; };

template<size_t N>
struct foo
{
    enum{D = (N > 32 ? 3 : (N > 16 ? 2 : (N > 8 ? 1 : 0)))};

    typedef typename select<D>::result value_type;

    value_type value;
};

In you can use std::conditional:

typedef 
    typename std::conditional<(N > 32), uint64_t,
    typename std::conditional<(N > 16), uint32_t,
    typename std::conditional<(N > 8), uint16_t, uint8_t>
    ::type>::type>::type value_type;

You can decide which one is less readable.

hansmaad
  • 18,417
  • 9
  • 53
  • 94
  • 2
    Great answer. Shouldn't the enum be `enum{D = (N > 32 ? 3 : (N > 16 ? 2 : (N > 8 ? 1 : 0)))};`, though? Here's it working: http://ideone.com/OgXaz – filipe Oct 04 '11 at 17:49
  • Oh wow, I've done this in the past, but this is _much_ simpler than my version! Though mine had bool(1), char(2-8), ..., long long(33-64), and void(65+) – Mooing Duck Oct 04 '11 at 18:32
  • @filipe Thank you for the complete test, you are right! – hansmaad Oct 05 '11 at 06:00
7

@hansmaad answer is a nice answer, but I would prefer to use (guess what?!) Boost:

boost::uint_t<N>::least // N: bits

The smallest, built-in, unsigned integral type with at least N bits. The parameter should be a positive number. A compile-time error results if the parameter is larger than the number of bits in the largest integer type.

Khaled Alshaya
  • 94,250
  • 39
  • 176
  • 234
  • Very cute, even more so as I am using boost in my project, but it does not handle the case of foo<72>::value_type resolving to the largest available integer. – Freddie Witherden Oct 04 '11 at 20:04
1

Template parameters need to be concrete, so I don't think there's any way to avoid specializing for each required value.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622