0

I'm currently trying to implement a small template which deduces the type needed to store a certain number of bits given as template parameter:

template<unsigned char BITS>
class Register
{
public:
    unsigned long type;
};

Furthermore I'm trying to specialize this template for certain bit sizes:

template<>
class Register<8>
{
public:
    unsigned char type;
};

template<>
class Register<16>
{
public:
    unsigned short type;
};

template<unsigned int N> Register<N+1>;

Unfortunately this doesn't work as intended and fails to compile:

int _tmain(int argc, _TCHAR* argv[])
{
    Register<32>::type val32 = 0xDEADBEEF;
    assert(sizeof(val) == sizeof(unsigned long) );

    Register<16>::valType val16 = 0xBEEF;
    assert(sizeof(val) == sizeof(unsigned short) );

    Register<8>::valType val8 = 0xEF;
    assert(sizeof(val) == sizeof(unsigned char) );

    Register<4>::valType val4 = 0xF;
    assert(sizeof(val) == sizeof(unsigned char) );

    return 0;
}

Maybe someone can give me a pointer to some helpful text or tell me what's wrong with my approach?

fhw72
  • 1,066
  • 1
  • 11
  • 19

1 Answers1

5

You want a type member, not a data member:

template <std::size_t N> struct Register
{
    using type = unsigned long int;
};

template <> struct Register<8>
{
    using type = unsigned char;
};

// ...

Usage:

template <typename T> void f()
{
    typename Register<sizeof(T) * CHAR_BIT>::type thing;
    // ...
}
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Thanks. I totally overlooked that. Can this template be extended to all other parameter values (1-32) in a generic way? That means that e.g. Register<17> automatically selects the Register<32> declaration? – fhw72 Apr 22 '16 at 10:52
  • 1
    @fhw72: Sure. You can have some intermediate dispatching mechanism that "snaps" to the nearest implemented value, etc. – Kerrek SB Apr 22 '16 at 10:59
  • Can this also be achieved at compile time? Like Register uses Register.... and so on and eventually "snaps" in at the next explicit defined template? – fhw72 Apr 22 '16 at 11:02
  • Yes, you can compute "N+1" at compile time, and also things like "(N+7)/8*N" etc. – Kerrek SB Apr 22 '16 at 11:07
  • Could you please give me an example? I don't get it currently. BTW: I thought in this "recursive" direction: template struct Register { using type = Register::type; }; – fhw72 Apr 22 '16 at 11:11
  • @fhw72: How about: `template using RegisterType = typename Register<(N + 7) / 8 * N>::type;`. Now you can say `RegisterType<17>` and you get `Register<24>::type`. – Kerrek SB Apr 22 '16 at 11:34
  • I don't have 24Bit registers on the platform. So I tried: template using RegisterType = typename Register::type; Doesn't work unfortunately. – fhw72 Apr 22 '16 at 11:42
  • OK - I mean, you can write down any mathematical expression you like. As long as it's a constant expression, you can use it. – Kerrek SB Apr 22 '16 at 14:25