#include <type_traits>
template<typename T>
void f(T&& a, T&& b)
{}
int main()
{
int n;
f(n, std::move(n));
}
T&&
is a forwarding reference type, so I think decltype(a)
should be int&
and decltype(b)
should be int&&
.
However, the code above generates the following error:
main.cpp(13,2): error : no matching function for call to 'f' f(n, std::move(n));
main.cpp(7,6): note: candidate template ignored: deduced conflicting types for parameter 'T' ('int &' vs. 'int')
void f(T&& a, T&& b)
1 error generated.
Why does it not work when an lvalue-ref-arg and an rvalue-ref-arg are passed as the same forwarding-ref type?
My compiler is clang 4.0.
The compiler error is pretty straight forward, T
cannot be deduced in int&
and int
at the same time. In order for this to work you would have to provide an additional template argument:
template<typename T1, typename T2>
void f(T1&& a, T2&& b)
{}
Template argument deduction follows special rules when dealing with forwarding references (a.k.a Universal references) which are based on reference collapsing rules
for example if you have a function template:
template<typename T>
void foo(T&&) {}
foo
input is an lvalue of type U
, T
will be deducted to U&
. Following the reference collapsing rules above the argument type will become U&
.foo
input is a rvalue of type U
, T
will be deducted to U
and consequently the argument type will be U&&
.Now following the reasoning above, template argument deduction will deduce T
into int&
for your first argument since input is an lvalue
.
Template argument deduction will try to match the type of the second argument but for the second argument since input is an rvalue following the rules above T
will be deduced to int
.
At this point the compiler throws its hands up in the air and screams "dude T
's deducted type must match for all input arguments".