OK, I've spent half my afternoon to find a solution without using any macro (because macros are evil (C++ FAQ lite) and we want something more portable) and without execution penalty (in other words, everything is done compile-time). My code is a bit generic, so it may suit other situations.
The key is to use templates to make compile-time decisions on the type of a typedef. First, we have to make a kind of static linked list of types using templates, and make a meta-programmed algorithm to find the desired type that have the sizeof we want.
Code:
// we have to make such a static linked list of type.
// so that's the basic definition, and later we'll link it with himself
template<typename T, typename U>
struct type_list
{
//those members are facultative here, but might be useful
typedef T head;
typedef U tail;
};
// but to find the end of such a list, we have to define it
class Empty{};
// and now, we make our list of unsigned integral type
typedef type_list<
unsigned char, type_list<
unsigned wchar_t, type_list<
unsigned short, type_list<
unsigned int, type_list<
unsigned long int, type_list<
unsigned long long int, Empty>
>
>
>
>
>
unsigned_integral_type_list;
// that class will perform the actual research algorithm
template<unsigned size_of, typename T>
class find_type_with_n_bytes;
// anything that doesn't match something below will lead to compile error.
template<unsigned size_of, typename head, typename tail>
class find_type_with_n_bytes<size_of,type_list<head, tail> >
{
// in the private field we have another struct that will truly do the job
// using recursion, at compile-time.
template<bool, unsigned, typename, typename>
struct research_type_by_size_of;
// this is the case when we have found the type.
template<unsigned my_size_of,typename _result, typename _any>
struct research_type_by_size_of<true, my_size_of, _result, _any >
{
typedef _result _type;
};
//this is the case when the type is not found, and we're at the end of
// the list. We typedef the struct type_not_found so when trying to
// actually use the type, it will fail to compile with a fairly explicit
// error like " illegal use of 'struct type_not_found' "
template<unsigned my_size_of, typename _result>
struct research_type_by_size_of<false, my_size_of, _result, Empty >
{
typedef struct type_not_found _type;
};
// the recursive case, when the type is not found and we're not yet at
// the end of the list.
template<unsigned my_size_of,typename _result, typename _head, typename _tail>
struct research_type_by_size_of<false, my_size_of, _result, type_list< _head, _tail > >
{
typedef typename research_type_by_size_of<(sizeof(_head)== my_size_of), my_size_of, _head, _tail >::_type _type;
};
public:
// what the user can use.
typedef typename research_type_by_size_of<(sizeof(head)== size_of), size_of, head, tail >::_type result;
};
int main(int,char *[])
{
// how to use:
typedef find_type_with_n_bytes<2,unsigned_integral_list_type>::result myUInt_16_t;
//do whatever you want with
myUInt_16_t a, b, c = b = a = 0;
return 0;
}
Note: I suspect there's something in the C++ Boost library that already addresses the issue, but I didn't checked out, probably because I wanted to take that challenge