Reputation: 15387
I have a bunch of functions overloaded for all of the [u]int{8|16|32|64}_t
types:
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.)
I now 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 produces an error:
error: call of overloaded 'f(long unsigned int&)' is ambiguous
This happens, I suppose, because unsigned int
and uint32_t
are different types. But, I can't overload the function more 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 the type mechanisms are working against each other: it can't figure out which conversion to use because each conversion is equally valid, but a no-conversion overload can't be defined because it already has been.
I can't cast the argument for various reasons. Is there a way out of this?
Platform is g++ MinGW x86 running on Windows 7 x86-64.
Upvotes: 9
Views: 7074
Reputation: 2987
Since you're defining overloads for (nearly?) every type, perhaps your function should be a template instead?
template < typename T >
std::string f( T )
{
/*something*/
}
If there is one set of code that works for all - or even most - types, that would save you a lot of work as well.
If for some reason you still need to force the call with the unsigned long int
value to treat it as some other type (like uint32_t
), you could specify the template instantiation at the call-site:
return f<uint32_t>( *internal_variable );
Upvotes: 0
Reputation: 2987
What platform are you using?
On Windows (Visual Studio 2010), unsigned long int
is a distinct type from the others you mentioned.
Adding an overload specifically for that type resolved the error. This answer (and/or Google) may shed more light on the issue: Type of unsigned long is different from uint32_t and uint64_t on Windows (VS2010).
I defined an overload for unsigned long int
like so:
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 so:
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
Upvotes: 1
Reputation: 129494
The following is my "test" based on the code provided 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;
}
Sample output:
$ 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 run with clang++, but the results are the same for g++)
This makes sure that both the unsigned long
and unsigned long long
types are covered. Unfortunately, one of those is uint64_t
, so it has to be removed.
If you do declare variables as unsigned long
, you must supply a function that takes exactly that - and relying on it being equivalent to uint32_t
is probably incorrect - even if they are the same bitsize.
Upvotes: 0