Monday, May 14, 2012

Determine number of bits in integral type at compile time

I have a C library with functions like

obj_from_int32(int32_t& i);
obj_from_int64(int64_t& i);
obj_from_uint32(uint32_t& i);
obj_from_uint64(uint64_t& i);

In this case the types int32_t etc are not the std ones - they are implementation defined, in this case an array of chars (in the following example I've omitted the conversion - it doesn't change the question which is about mapping intergral types to a particular function based on the number of bits in the integral type).

I have a second C++ interface class, that has constructors like

MyClass(int z);
MyClass(long z);
MyClass(long long z);
MyClass(unsigned int z);
MyClass(unsigned long z);
MyClass(unsigned long long z);

Note, I can't replace this interface with std::int32_t style types - if I could I wouldn't need to ask this question ;)

The problem is how to call the correct obj_from_ function based on the number of bits in the integral type. I have tried the following:

// Helper functions
objFromInt(boost::int_t<32>::exact z) { return obj_from_int32(z); }
objFromInt(boost::int_t<64>::exact z) { return obj_from_int64(z); }
objFromInt(boost::uint_t<32>::exact z) { return obj_from_int32(z); }
objFromInt(boost::uint_t<64>::exact z) { return obj_from_int64(z); }

// Interface Implementation
MyClass(int z) : _val(objFromInt(z)) {}
MyClass(long z): _val(objFromInt(z)) {}
MyClass(long long z): _val(objFromInt(z)) {}
MyClass(unsigned int z): _val(objFromInt(z)) {}
MyClass(unsigned long z): _val(objFromInt(z)) {}
MyClass(unsigned long long z): _val(objFromInt(z)) {}

The intent is the compiler will pick the correct overload for the integral type, and boost does the hard work behind the scenes mapping the number of bits to types for each architecture.

The problem is this fails on gcc (4.6.3) (but not of MSVC - so I've been given (false?) hope!). The error is:

In constructor 'MyClass(long int)':
error: call of overloaded 'objFromInt(long int&)' is ambiguous
note: candidates are:
note: objFromInt(boost::int_t<32>::exact)
note: objFromInt(boost::uint_t<64>::exact)
note: objFromInt(boost::int_t<32>::exact)
note: objFromInt(boost::uint_t<64>::exact)

This error is repeated for the long unsigned int& version of the constructor. So, the it appears only the long type causes the problem (although more errors unreported errors could be lurking).

I suspect the root of the problem is int and long are the same size on my architecture: 32 bits, but still would have thought both would just resolve to call obj_from_int32.

Any ideas how to solve this?

(This incorporates suggested solutions - thanks!!)

  • boost::int_t<32>::least instead of exact

  • Not having signed and unsigned in the same overload set (ie have 'objFromInt' and 'objFromUInt')

No comments:

Post a Comment