问题
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 )!
回答1:
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.
回答2:
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);
回答3:
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).
回答4:
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.
来源:https://stackoverflow.com/questions/4610503/how-to-resolve-ambiguity-of-call-to-overloaded-function-with-literal-0-and-point