6

I'm using a template to convert integral types into a string representation of their binary values. I used the following:

template<typename T>
std::string ToBinary(const T& value)
{
    const std::bitset<std::numeric_limits<T>::digits + 1> bs(value);
    const std::string s(bs.to_string());

    return s;
}

It works for int but doesn't compile with unsigned int :

unsigned int buffer_u[10];
int buffer_i[10];
...
ToBinary(buffer_i[1]); //compile and works
ToBinary(buffer_u[1]); //doesn't compile -- ambiguous overload

Could you explain why?

EDIT:

Yes, I'm using VS2010

Heisenbug
  • 38,762
  • 28
  • 132
  • 190
  • What compiler are you using? This: `const std::bitset<33> bs(buffer_u[1]);` produces an ambiguous overload error on VC2010 but compiles fine with g++ 3.4.6. – hmjd Jan 25 '12 at 11:05

3 Answers3

4

Not your ToBinary call is ambiguous, its the constructor call of bitset with an unsigned value. Unfortunately this is a VC++ Bug: http://connect.microsoft.com/VisualStudio/feedback/details/532897/problems-constructing-a-bitset-from-an-unsigned-long-in-the-vc-rc

Edit - Workaround:

template<>
std::string ToBinary<unsigned int>(const unsigned int& value)
{
    const std::bitset<std::numeric_limits<unsigned int>::digits> bs(static_cast<unsigned long long>(value));
    return bs.to_string();
}
KasF
  • 212
  • 1
  • 6
  • specialize the template for unsigned int and use unsigned long long as suggested in the solution and trim the result back to std::numeric_limits::digits or use it already as N for the bitset – KasF Jan 25 '12 at 14:07
0

Are you using VC10? There is already an issue reported: Microsoft connect. Also I'd guess that you might be able to fix it by casting the type to int if it is 32 bit, like this:

string s = ToBinary(*reinterpret_cast<int*>(&buffer_u[1]));

This can be done inside of the method as well if needed. The result of the reinterpret should not be used for arithmetics anymore, though. ;)

Works fine as workaround for me (but looks quite ugly)

template<typename T>
std::string ToBinary(const T& value)
{
    switch (sizeof(T))
    {
    case 8:
        return std::bitset<std::numeric_limits<T>::digits + 1>(*reinterpret_cast<const long*>(&value)).to_string();
    case 4:
        return std::bitset<std::numeric_limits<T>::digits + 1>(*reinterpret_cast<const int*>(&value)).to_string();
    case 2:
        return std::bitset<std::numeric_limits<T>::digits + 1>(*reinterpret_cast<const short*>(&value)).to_string();
    case 1:
        return std::bitset<std::numeric_limits<T>::digits + 1>(*reinterpret_cast<const char*>(&value)).to_string();
    }
    return "n/a";
}
Coder02
  • 260
  • 2
  • 8
  • it compiles but it doesn't work (raises access violation exception) – Heisenbug Jan 25 '12 at 12:14
  • Really? Works perfectly fine for me - instead of index operator, you can use `*reinterpret_cast(buffer_u+1)`as well. I updated the answer above including a changed ToBinary. – Coder02 Jan 25 '12 at 13:43
0

If you look at the standard (FDIS n3290), then you see that std::bitset has multiple constructors:

First there is this one:

20.5.1 bitset constructors [bitset.cons]

constexpr bitset(unsigned long long val) noexcept;

Effects: Constructs an object of class bitset, initializing the first M bit positions to the corresponding bit values in val. M is the smaller of N and the number of bits in the value representation (3.9) of unsigned long long. If M < N, the remaining bit positions are initialized to zero.

Then there is also this one, which I suspect might be might cause things to become ambigious, when you call it with unsigned int

template <class charT>
explicit bitset(
const charT* str,
typename basic_string<charT>::size_type n = basic_string<charT>::npos,
charT zero = charT(’0’), charT one = charT(’1’));

Effects: Constructs an object of class bitset as if by

bitset( n == basic_string<charT>::npos ? basic_string<charT>(str) :
basic_string<charT>(str, n), 0, n, zero, one)
Tony The Lion
  • 61,704
  • 67
  • 242
  • 415
  • No, an integer never voluntarily converts to a pointer, you have to force it with a cast. – Xeo Jan 25 '12 at 11:31