Simple solution
Add an overload that is callable with an rvalue of type NoBuzz.
void foo(NoBuzz const&){ };
void foo(NoBuzz&&) { }; // overload for rvalues
Note: Depending on your actual use case this might not be enough, because if you pass a non-const lvalue type NoBuzz to foo
you'd still instantiate the template, since the two NoBuzz
overloads doesn't match.
At the end of this post is a more complex, but certainly cleaner, solution.
Explanation
template<class T>
void foo (T&&); // (A)
void foo (NoBuzz const&); // (B)
The problem with your snippet is that your template (A) can be instantiated in such a way that it's a better match than your overload (B).
When the compiler sees that you are trying to call a function named foo with an argument which is an rvalue of type NoBuzz
, it will look for all functions named foo taking one argument where a NoBuzz
would fit.
Let's say it starts of with your template (A), here it sees that T&&
is deducable to any reference type (both lvalue, and rvalue), since we are passing an rvalue T = NoBuzz
.
With T = NoBuzz
the instantiated template would be semantically equivalent to:
void foo (NoBuzz&&); // (C), instantiated overload of template (A)
It will then continue to your overload (B). This overload accepts a const lvalue reference, which can bind to both lvalues and rvalues; but our previous template instantiation (C) can only bind to rvalues.
Since (C) is a better match than (B), binding rvalues to T&&
is prefered over U const&
, that overload is selected and you get the behavior you describe in your post.
Advanced solution
We can use a technique called SFINAE to conditionally make it impossible to call the template if the type passed doesn't implement .buzz ()
.
template <typename T>
auto foo(T&& t) -> decltype (t.buzz ())
{
return t.buzz();
}
The above solution uses a lot of new features of C++11, detailed information is available here: