函数模板推导左值引用和通用引用
Function template deduction l-value reference and universal reference
假设我有函数 copy
:
template <typename Buf>
void copy(
Buf&& input_buffer,
Buf& output_buffer)
{}
其中input_buffer
是通用引用,output_buffer
是左值引用。
Reference collapsing rules
确保 input_buffer
确实是一个通用引用,而不管 Buf
的推导类型如何,而 output_buffer
确实是一个左值引用。
但是,我想知道Buf
类型是如何推导出来的。
我发现 copy
传递了一个右值 input_buffer
,(显然传递了一个左值 output_buffer
)Buf
是非-引用类型。
但是,如果我要传递两个左值,程序将无法编译:
int i = 4;
int j = 6;
_copy(i, j);
我希望编译器将 Buf
推断为 int&
。遵循引用折叠规则,我希望 input_buffer
成为左值引用,即 & + && -> &
,并且 output_buffer
也成为左值引用; & + & -> &
.
所以问题是:为什么这段代码不能编译?
(注:我不是求问题的解决方法,而是求解释。)
如果我需要详细说明,请随时询问。
编辑:
如果打电话:copy(i, j);
GNU GCC 编译器给出:
错误:没有匹配函数来调用 'copy(int&, int&)'
注意:候选:template void copy(Buf&&, buf&)
注意:模板参数 deduction/substitution 失败:
注意:推断出参数 'Buf' 的冲突类型('int&' 和 'int')
如果调用:
copy<int&>(i, j);
好的。
a) 转发引用的类型推导:
template<class T>
void f(T&& val) {}
[a.1] 当你传递左值时 T
被推导为 T&
。所以你有
void f(T& && ){} -after reference collapsing-> void f(T&){}
[a.2] 当你传递右值时 T
被推断为 T
。所以你有
void f(T&& ) {}
b) 除转发引用:
外引用的类型推导
template<class T>
void f(T& param){}
当你传递左值时,T
被推导为T
。 param
具有类型 T&
但模板参数是 T
,而不是 T&
。
所以下面的代码可以编译
int i = 10;
copy(20,i);
因为第一个参数的类型推导 returns Buf==int
因为你传递了 20 个右值。
第二个参数的推导结果也是 returns Buf==int
。所以在两者
cases Buf
相同,代码编译。
无法编译的代码:
int i=1;
int j=2;
copy(i,j);
第一个参数的推导类型是什么?您传递的是 L 值,因此 Buf
是 int&
。
二扣returnsBuf==int
。这两个推导的类型不一样,这就是为什么
代码无法编译。
假设我有函数 copy
:
template <typename Buf>
void copy(
Buf&& input_buffer,
Buf& output_buffer)
{}
其中input_buffer
是通用引用,output_buffer
是左值引用。
Reference collapsing rules
确保 input_buffer
确实是一个通用引用,而不管 Buf
的推导类型如何,而 output_buffer
确实是一个左值引用。
但是,我想知道Buf
类型是如何推导出来的。
我发现 copy
传递了一个右值 input_buffer
,(显然传递了一个左值 output_buffer
)Buf
是非-引用类型。
但是,如果我要传递两个左值,程序将无法编译:
int i = 4;
int j = 6;
_copy(i, j);
我希望编译器将 Buf
推断为 int&
。遵循引用折叠规则,我希望 input_buffer
成为左值引用,即 & + && -> &
,并且 output_buffer
也成为左值引用; & + & -> &
.
所以问题是:为什么这段代码不能编译?
(注:我不是求问题的解决方法,而是求解释。)
如果我需要详细说明,请随时询问。
编辑:
如果打电话:copy(i, j);
GNU GCC 编译器给出:
错误:没有匹配函数来调用 'copy(int&, int&)'
注意:候选:template void copy(Buf&&, buf&)
注意:模板参数 deduction/substitution 失败:
注意:推断出参数 'Buf' 的冲突类型('int&' 和 'int')
如果调用:
copy<int&>(i, j);
好的。
a) 转发引用的类型推导:
template<class T>
void f(T&& val) {}
[a.1] 当你传递左值时 T
被推导为 T&
。所以你有
void f(T& && ){} -after reference collapsing-> void f(T&){}
[a.2] 当你传递右值时 T
被推断为 T
。所以你有
void f(T&& ) {}
b) 除转发引用:
外引用的类型推导template<class T>
void f(T& param){}
当你传递左值时,T
被推导为T
。 param
具有类型 T&
但模板参数是 T
,而不是 T&
。
所以下面的代码可以编译
int i = 10;
copy(20,i);
因为第一个参数的类型推导 returns Buf==int
因为你传递了 20 个右值。
第二个参数的推导结果也是 returns Buf==int
。所以在两者
cases Buf
相同,代码编译。
无法编译的代码:
int i=1;
int j=2;
copy(i,j);
第一个参数的推导类型是什么?您传递的是 L 值,因此 Buf
是 int&
。
二扣returnsBuf==int
。这两个推导的类型不一样,这就是为什么
代码无法编译。