问题
Let's say I have the function copy
:
template <typename Buf>
void copy(
Buf&& input_buffer,
Buf& output_buffer)
{}
In which input_buffer
is a universal reference and output_buffer
is an l-value reference.
Reference collapsing rules
make sure input_buffer
is indeed, regardless of the deduced type of Buf
, an universal reference and output_buffer
is indeed an l-value reference.
However, I wonder how type Buf
is deduced here.
I found out that copy
is passed an r-value as input_buffer
, (and an l-value as output_buffer
, obviously) Buf
is a non-reference type.
If I were to pass two l-values however, the program does not compile:
int i = 4;
int j = 6;
_copy(i, j);
I would expect the compiler to deduce Buf
to int&
. Following the reference collapsing rules, I would expect input_buffer
to become an l-value reference, that is, & + && -> &
, and output_buffer
to become an l-value reference too; & + & -> &
.
So the question is: Why doesn't this code compile?
(Note: I am not necessarily asking for a solution to the problem, but for an explanation.)
If I need to elaborate, feel free to ask.
EDIT:
if call: copy(i, j);
GNU GCC Compiler gives:
error: no matching function for call to 'copy(int&, int&)'
note: candidate: template void copy(Buf&&, buf&)
note: template argument deduction/substitution failed:
note: deduced conflicting types for parameter 'Buf' ('int&' and 'int')
if call:
copy<int&>(i, j);
OK.
回答1:
a) Type deduction for forwarding reference:
template<class T>
void f(T&& val) {}
[a.1] when you pass Lvalue T
is deduced to be T&
. So you have
void f(T& && ){} -after reference collapsing-> void f(T&){}
[a.2] when you pass Rvalue T
is deduced to be T
. So you have
void f(T&& ) {}
b) Type deduction for reference except forwarding reference:
template<class T>
void f(T& param){}
when you pass Lvalue, T
is deduced to be T
. param
has type T&
but template argument is T
, not T&
.
So below code compiles
int i = 10;
copy(20,i);
because type deduction for first argument returns Buf==int
since you passed 20 Rvalue.
And result of deduction for second argument also returns Buf==int
. So in both
cases Buf
is the same, code compiles.
Code which doesn't compile:
int i=1;
int j=2;
copy(i,j);
What is deduced type for first argument? You are passing L-value, so Buf
is int&
.
Second deduction returns Buf==int
. These two deduced types are not the same, that is why
code doesn't compile.
来源:https://stackoverflow.com/questions/53175851/function-template-deduction-l-value-reference-and-universal-reference