This piece of metaprogramming trickery achieves it:
template<unsigned int Y> struct typed
{
typedef typename typed<(Y & (Y - 1)) == 0 ? Y / 2 : (Y & (Y - 1))>::type type;
};
template<> struct typed<0>
{
typedef std::uint8_t type;
};
template<> struct typed<256>
{
typedef std::uint16_t type;
};
template<> struct typed<65536>
{
typedef std::uint32_t type;
};
/* ToDo - add more specialisations as necessary*/
template<unsigned k> class A
{
public:
unsigned static const k_ = k; /*constexpr if your compiler supports it*/
typename typed<k>::type u_;
};
The usage is exactly in the question.
The unspecialised template version takes the previous type. typed<0>
blocks the static recursion. The other specialisations act as anchoring points for the appropriate types.
The compile-time evaluable (Y & (Y - 1)) == 0 ? Y / 2 : (Y & (Y - 1))
reduces the number of instantiations by removing the rightmost bit of Y
until a power of 2 is reached, and then divides by 2 subsequently to that. (Acknowledge @Jarod42).
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…