How to resolve ambiguity of call to overloaded function with literal 0 and pointer
I'm pretty sure this must have been here already, but I didn't find much information on how to solve this kind of problem (without casting on the call):
Given two overloads, I want that a call with function with a literal 0 always calls the unsigned int version:
void func( unsigned int ) {
cout << "unsigned int" << endl;
}
void func( void * ) {
cout << "void *" << endl;
}
func( 0 ); // error: ambiguous call
I understand why this happens, but I don't want to write func( 0u ) or even func( static_cast(0) ) all the time. So my questions are:
1) Is there a recommended way to do开发者_高级运维 this in general?
2) Is there any problem with doing it the following way and what is the reason that this to works?
void func( unsigned int ) {
cout << "unsigned int" << endl;
}
template <typename T>
void func( T * ) {
static_assert( std::is_same<T, void>::value, "only void pointers allowed" );
cout << "void *" << endl;
}
func( 0 ); // calls func( unsigned int )!
What you're doing in 2) works and is probably the better way to do it.
In situations where you don't want to change the functions, you can do an explicit cast to give the compiler a hint:
func((void *) 0);
func((unsigned int) 0);
I suggest you look at the null pointer from C++0x (see this). It defines a class representing null pointers of any type. The example you just gave was actually one motivating the inclusion of nullptr_t (the class) / nullptr (the value) to C++0x. It actually lets you disambiguate this call by putting 0 when wanting the unsigned int version, and nullptr when you want the other.
You may just implement this trick in a little utility class until your compiler supports it (or just use it if your compiler implements this part of the next standard).
1) Is there a recommended way to do this in general?
Yes, I would do it the way you did in 2). I don't think there is any deeper meaning as to why 2) works. The type int
simply doesn't match T*
, so it has no way to find out T
. It will therefor ignore the template.
1) Is there a recommended way to do this in general?
The problem is simply that the literal 0
is an int
, not an unsigned int
, and there are valid conversions from int
to unsigned int
and from int
to void*
. I can't say that there's a recommended way to handle the problem. Aside from the ways you've already found, you could also add another overload:
void func(int i)
{
assert(i >= 0);
return func(static_cast<unsigned int>(i));
}
2) Is there any problem with doing it the following way and what is the reason that this to works?
The template trick works because the rules for resolving calls to functions that are overloaded and have templated versions are designed to prefer non-templated versions of the overloaded functions.
精彩评论