问题描述
C ++参考折叠规则的几个来源如下:
A& & becomes A&
A& && becomes A&
A&& & becomes A&
A&& && becomes A&&
(例如http://thbecker.net/articles/rvalue_references/section_08.html)
我可以举一个例子,让A &&&成为A&
template <class T> void f1(T&& param) {
// T t = 5; // does not compile because T is T&
param++; // param collapses from int&&&& to int&&
}
void demo()
{
int x = 8;
int &y = x;
f1(y); // OK T will still be int&,param will go to int&&& -> collapses to int&
cout << y; // prints 9
}
我希望A &&&&&类似的东西变成A &&,但是当我用RValue调用时,T被推导为int,因此这并没有显示我想要的东西。
template <class T> void f1(T&& param) {
T t = 5; // compiles since T is int
T t2 = t; // would not compile if T was int&&
t2++;
cout << t; // prints 5 since t2 was not a reference
}
void demo()
{
f1(8); // OK T deduced to int,param will go to int&&,no collapsing
}
有人可以帮我显示一个类似的示例,其中T推导为T &&,参数从T &&&&折叠为T &&吗?
解决方法
有人可以帮我显示一个类似的示例,其中T推导为T &&,参数从T &&&&折叠为T &&吗?
如果我们谈论的是实际的推论,而模板参数T
并未明确给出或没有默认设置,那是不可能的。原因是转发不仅依赖于参考折叠。
首先,我们必须注意,在C ++中,函数(模板)的参数始终是某种表达式。表达式永远不会具有引用类型。
[expr.type]
1如果表达式最初的类型为“对T的引用” ([dcl.ref],[dcl.init.ref]),将类型调整为T之前的任何 进一步分析。表达式指定对象或功能 由参考表示,并且表达式是左值或 xvalue,取决于表达式。
您实际上不能为引用类型的函数产生参数。因此,在正常情况下,T
不能推论为 。转发还依赖于模板中引用功能参数的特殊情况。
[临时扣除电话]
3如果P是引用类型,则P引用的类型用于 类型推演。 [...] 转发参考是一个右值参考 不代表模板的cv不合格模板参数 类模板的参数(在类模板参数期间) 扣除([over.match.class.deduct]))。如果P是转发参考 并且参数是左值,类型“对A的左值引用”是 代替A进行类型推导。
如您所见,转发引用是专门围绕作为参数提供的表达式的值类别而设计的。仅当表达式为左值时,参数的类型才被视为“对A的左值引用”。否则,将无法进行任何调整。因此,将T
推导为所引用的类型。
仅当明确给出type参数时,引用折叠规则才起作用。在这种情况下,当以某种方式提供int&&
时,我们将通过引用折叠获得右值引用。但这不是在模板参数 deduction 之后。
在评论员和其他答案发布者的帮助下,我提出了这个演示:
template <class T> void f1() {
int x = 5; // an lvalue
//T t1 = x; // compiles when T is int or int&,fails when T is int&
//T& t2 = x; // always compiles,becomes int&. Can check with ++t2; cout << x;
//T&& t3 = x; // compiles when T is int&,fails when t3 is &&
}
void demo()
{
//f1<int>(); // T becomes int,t1=int,t2=int& t3=int&&
//f1<int&>(); // T becomes int& t1=int& t2=int& t3=int&
f1<int&&>(); // T becomes int&&,t1=int&& t2=int&,t3=int&&
}