2

假设我有这个功能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传递了一个 r-value as input_buffer,(和一个 l-value as output_buffer,显然)Buf是一个非引用类型。

但是,如果我要传递两个 l 值,则程序不会编译:

int i = 4;
int j = 6;

_copy(i, j);

我希望编译器推断Bufint&. 遵循引用折叠规则,我希望input_buffer成为左值引用,即& + && -> &,并且output_buffer也成为左值引用;& + & -> &.

所以问题是:为什么这段代码不能编译?

(注意:我不一定要求解决问题,而是要求解释。)

如果我需要详细说明,请随时询问。

编辑:如果调用:copy(i, j); GNU GCC 编译器给出:错误:没有用于调用“复制(int&,int&)”的匹配函数注:候选:模板无效副本(Buf&&,buf&)注:模板参数推导/替换失败:注:推导参数“Buf”(“int&”和“int”)的冲突类型

如果打电话: copy<int&>(i, j); 好的。

4

1 回答 1

2

a)转发参考类型扣减:

template<class T>
void f(T&& val) {}

[a.1] 当你传递 Lvalue 时T,推断为T&. 所以你有了

void f(T& && ){} -after reference collapsing-> void f(T&){}

[a.2] 当你传递 Rvalue 时T,推断为T. 所以你有了

void f(T&& ) {}

b) 除转发参考外的参考类型扣除:

template<class T>
void f(T& param){}

当你传递 Lvalue 时,T推断为T. param有类型T&,但模板参数是T,不是T&

所以下面的代码编译

int i = 10;
copy(20,i);

因为第一个参数的类型推导返回Buf==int,因为您传递了 20 Rvalue。并且第二个参数的推导结果也返回Buf==int。所以在这两种情况下Buf都是一样的,代码编译。

无法编译的代码:

int i=1;
int j=2;
copy(i,j);

第一个参数的推导类型是什么?您正在传递 L 值,因此Buf也是如此int&。第二扣返还Buf==int。这两种推导的类型不一样,这就是代码无法编译的原因。

于 2018-11-06T17:15:41.957 回答