The whole premise about forwarding references (aka universal references) is, that this function:
template<typename T>
void f(T&&) { }
can result in the template parameter either being int&
or int
, depending if you call it with int a{}; f(a)
or f(5)
as example. But this is already a step too far I think. Because when I have a function like
template<typename T>
auto g(T) -> void {}
Then it always resolves the template parameter to int
, regardless of the way I call it. And that although a auto h(int&) -> void {}
is perfectly legal.
So what what rules are in place that allow the template parameter of f
to be a reference, but not that of g
?
CodePudding user response:
There is a specific exception in the template argument deduction rules for the case that a function parameter has the form T&&
(cv-unqualified) where T
is a template parameter. This special case is as seen in the question known as a forwarding reference.
For forwarding references, if the function argument is an lvalue, then an lvalue reference is deduced for T
where usually no reference type would be deduced.
You can see that this really is a special rule just for this case by trying to use e.g. const T&&
instead of T&&
, for which the special rule does not apply. It will deduce a non-reference type for T
in any case, although the function call may then not be possible.
CodePudding user response:
you can read Effective modern C for the answer, first chapter, it says that ,we can think of a function template as looking like this:
template<typename T>
void f(paramType param);
T
and paramType
is often differnent, paramType often contains adornments like const or reference qualifiers like const T&
and he talked about this in three cases
- paramType is a pointer or reference type
- paramType is a universal reference
- paramType is neither a pointer nor a reference
your first function is case2, since it needs to deduce the type, &&
here is a universal reference, and your second function is case3, paramType is neither a pointer nor a reference
During type deduction for a template parameter that is a universal reference, lvalues and rvalues of the same type are deduced to have slightly different types.
- lvalues of type T are deduced to be of type T&
- rvalues of type T are deduced to be type T
so f(a)
you got f(int& && param)
then it comes to the rule of "reference collapsing"
- rvalue reference to rvalue reference become rvalue reference
- all other references to references collapse into an lvalue reference
so you got f(int& param)