Reputation: 788
I am confused about c++ overload resolution between template and non-template functions, following is the sample:
class Stream {};
struct M
{
M(float v) {}
};
template <class T>
Stream& operator<<(Stream& stream, T& v) {}
Stream& operator<<(Stream& stream, const M& v) {}
int main()
{
Stream stream;
int a = 1;
stream << a; // sample 1
stream << a * a; // sample 2
return;
}
Here, sample 1 calls the template function. Sample 2 provides an int&&
type parameter, which can implicitly cast to const M&
, calls the non-template one, rather then the template one with T = const int
.
What happen in overload resolution with sample 2 ?
Upvotes: 3
Views: 808
Reputation: 181057
This really doesn't have anything to do with templates. In
stream << a * a;
a * a
materializes an rvalue. Since your template function takes a T&
it cannot bind to the temporary so it is discarded as a viable overload.
That leaves you with a user defined conversion to a M
and
Stream& operator<<(Stream& stream, const M& v)
as the only viable overload.
If you change your template to use a forwarding reference like
template <class T>
Stream& operator<<(Stream& stream, T&& v)
then that will be called in both cases as you will get an exact match. Do note that you should constrain T
using SFINAE otherwise this overload will be a match for piratically everything.
Additionally you could use
template <class T>
Stream& operator<<(Stream& stream, const T& v)
Upvotes: 5
Reputation: 62613
When used with an lvalue, template is a better match, because it doesn't require calling conversion from int
to M
.
However, since non-const lvalue references can't bind to rvalues (which is yield by multiplication) this overload can't be used, so the compiler falls back to the conversion.
Upvotes: 2
Reputation: 173044
The template one takes parameter by T&
, i.e. lvalue-reference to non-const. a * a
is an rvalue, which can't be bound to lvalue-reference to non-const (BTW it could be bound to lvalue-reference to const or rvalue-reference). Then the template one won't be considered.
Upvotes: 2