I have a function which can accept any type by universal reference, and would like to overload it for specific types (some of which are templated themselves, although I don't think that's important here). Unfortunately I can't quite seem to to get the overloads to be resolved in the right order.
I would have presumed that the second declaration of foo
would be preferred as it's more specific (less templated), although it looks like my understanding of overload resolution is lacking somewhat. Interestingly changing the second declaration to take X
by value makes it print "good, good" and making it take X
by non-const reference makes it print "bad, good". Obviously removing the first declaration entirely makes it return "good, good", as there's no other choice.
So why does this happen? And most importantly, if the following code doesn't work, how can you overload a function with this signature?
#include <iostream>
#include <string>
class X {};
template<typename T>
inline std::string foo(T && rhs) {
return "bad";
}
inline std::string foo(const X & rhs) {
return "good";
}
int main() {
std::cout << foo(X()) << std::endl;
X x;
std::cout << foo(x) << std::endl;
return 0;
}
Edit:
Maybe a more roundabout solution to this is to do it indirectly. Get rid of the first form of foo
and use SFINAE to check if a valid overload exists, it it doesn't then call foo_fallback
.