Ambiguous call to "long unsigned int" for "uint32_t"

I have a bunch of functions overloaded for all types of [u]int{8|16|32|64}_t :

 std::string f( uint8_t) { /*something*/ } std::string f( int8_t) { /*something*/ } std::string f(uint16_t) { /*something*/ } std::string f( int16_t) { /*something*/ } std::string f(uint32_t) { /*something*/ } std::string f( int32_t) { /*something*/ } std::string f(uint64_t) { /*something*/ } std::string f( int64_t) { /*something*/ } //A few more overloads with a few more types (bool, float, const char*, etc.) 

Now I call the function name with an argument of type long unsigned int :

 template <typename type_blah> class Something { public: //... std::string call_f(void) const { return f(*((type_blah*)(internal_variable))); } //... }; 

This causes an error:

error: calling overloaded 'f (long unsigned int &)' is ambiguous


This happens, I suppose, because unsigned int and uint32_t are different types. But I can no longer overload the function anymore for long unsigned int , because this is a redundant definition. I.e:.

 std::string f(long unsigned int) { /*something*/ } 

., produces:

error: 'std :: string f (uint32_t)' previously defined here


It seems that type mechanisms work against each other: it cannot determine which transformation to use, because each transformation is equally valid, but congestion without conversion cannot be determined, since it already was.

I cannot use the argument for various reasons. Is there a way out of this?

The g ++ MinGW x86 platform runs on Windows 7 x86-64.

+8
c ++
source share
3 answers

Below is my β€œtest” based on the code above:

 #include <string> #include <cstdint> #include <iostream> std::string f( uint8_t) { return "ui8";} std::string f( int8_t) { return "i8";} std::string f(uint16_t) { return "ui16";} std::string f( int16_t) { return "i16";} std::string f(uint32_t) { return "ui32";} std::string f(unsigned long long int) { return "unsigned long long";} std::string f(unsigned long int) { return "unsigned long";} std::string f( int32_t) { return "i32";} //std::string f(uint64_t) { return "ui64";} std::string f( int64_t) { return "i64";} int main() { unsigned long x = 42; unsigned y = 17; uint32_t z = 9; uint64_t w = 135; std::cout << "x: "<< f(x) << " y: " << f(y) << " z: " << f(z) << " w: " << f(w) << std::endl; } 

Output Example:

 $ clang++ ambig.cpp -std=c++0x -Wall -m64 $ ./a.out x: unsigned long y: ui32 z: ui32 w: unsigned long $ clang++ ambig.cpp -std=c++0x -Wall -m32 $ ./a.out x: unsigned long y: ui32 z: ui32 w: unsigned long long 

(I copied my launch using clang ++, but the results are the same for g ++)

This ensures that the unsigned long and unsigned long long types are covered. Unfortunately, one of them is uint64_t , so you need to remove it.

If you declare variables as unsigned long , you must provide a function that accepts exactly this, and relying on the fact that it is equivalent to uint32_t is probably incorrect - even if they are the same.

0
source share

What platform are you using?

On Windows (Visual Studio 2010), an unsigned long int is a different type from the others you talked about.

Adding overload specifically for this type resolved the error. This answer (and / or Google) may shed light on the problem: The unsigned long type is different from uint32_t and uint64_t on Windows (VS2010) .

I defined overload for unsigned long int as follows:

 std::string f( unsigned long int val ) { // Check that we chose the correct corresponding type // (This may vary by platform!) assert( sizeof( unsigned long int ) == sizeof( uint32_t ) ); return f( static_cast<uint32_t>( val ) ); } 

... tested in Visual Studio 2010 like this:

 void main() { std::cout << "sizeof( unsigned long int ): " << sizeof( unsigned long int ) << std::endl; std::cout << "sizeof( uint32_t ): " << sizeof( uint32_t ) << std::endl; unsigned long int x = 1u; std::cout << f( x ) << std::endl; } 

... and got the expected result:

 sizeof( unsigned long int ): 4 sizeof( uint32_t ): 4 uint32_t 
+1
source share

Since you define overloads for (almost?) Each type, maybe your function should be a template?

 template < typename T > std::string f( T ) { /*something*/ } 

If there is one set of code that works for all or even most types, it will also save you a lot of work.

If for some reason you still need to force a call using the unsigned long int value in order to treat it as some other type (for example, uint32_t ), you can specify the creation of an instance of the template on the call site:

 return f<uint32_t>( *internal_variable ); 
0
source share

All Articles