Search code examples
c++gccoverload-resolution

Ambiguous overload between int32_t or int64_t parameters when passing long


Note: This is very similar to Determine number of bits in integral type at compile time, however this is a much simplified version, all contained in a single .cpp

The problem is with functions like

 msg(int32_t);
 msg(int64_t);

a call like

long long myLong = 6;
msg(myLong);    // Won't compile on gcc (4.6.3), call is ambiguous

This compiles on MSVC. Can anyone provide an explanation of why this fails on gcc (I'm assuming it's probably to do with the fact gcc is usually strictly standards compliant) and an example of how to correctly achieve the same effect?

#include <iostream>
#include <stdint.h>

#include <boost/integer.hpp>

using namespace std;

void msg(int v) { cout << "int: " << sizeof(int) << ' ' << v << '\n'; }
void msg(long v) { cout << "long: " << sizeof(long) << ' ' << v << '\n'; }
void msg(long long v) { cout << "long long: " << sizeof(long long) << ' ' << v << '\n'; }

void msg2(int32_t v) { cout << "int32_t: " << sizeof(int32_t) << ' ' << v << '\n'; }
void msg2(int64_t v) { cout << "int64_t: " << sizeof(int64_t) << ' ' << v << '\n'; }
void msg2(uint32_t v) { cout << "uint32_t: " << sizeof(uint32_t) << ' ' << v << '\n'; }
void msg2(uint64_t v) { cout << "uint64_t: " << sizeof(uint64_t) << ' ' << v << '\n'; }


int main()
{
 
    int myInt = -5;
    long myLong = -6L;
    long long myLongLong = -7LL;

    unsigned int myUInt = 5;
    unsigned int myULong = 6L;
    unsigned long long myULongLong = 7LL;

    msg(myInt);
    msg(myLong);
    msg(myLongLong);

    msg2(myInt);
    msg2(myLong);     // fails on gcc 4.6.3 (32 bit)
    msg2(myLongLong);
  
    msg2(myUInt);
    msg2(myULong);   // fails on gcc 4.6.3 (32 bit)
    msg2(myULongLong);

   return 0;
}
// Output from MSVC  (and gcc if you omit lines that would be commented out)
int: 4 5
long: 4 6
long long: 8 7
int32_t: 4 -5
int32_t: 4 -6   // omitted on gcc
int64_t: 8 -7
uint32_t: 4 5
uint32_t: 4 6   // omitted on gcc
uint64_t: 8 7

Solution

  • Greg hits the nail on the head: int32_t and int64_t are typedefs which may or may not be long. If neither is a typedef for long, overload resolution can fail. Both long->int32_t and long->int64_t have Rank=Promotion (Table 12, 13.3.3.1.2)