?
?
?
?
?
?
?
4 cout << void F(A& a) << endl;
9 cout << void F(const long &a) << endl;
?
?
?
在未修改参数推导规则前,调用F(10)会选择第二个重载函数,但修改后,却会调用第一个重载函数,这就给C++带来了兼容性的问题。
?
?
?
?
?
?
?
?
?
修改后的针对右值引用的参数推导规则为:若函数模板的模板参数为A,模板函数的形参为A&&,则可分为两种情况讨论:
1、若实参为T&,则模板参数A应被推导为引用类型T&。(由引用叠加规则第2点T& + && = T&和A&&=T&,可得出A=T&)
2、若实参为T&&,则模板参数A应被推导为非引用类型T。(由引用叠加规则第4点T或T&& + && = T&&和A&&=T&&,可得出A=T或T&&,强制规定A=T)
?
?
?
当传给G一个左值(类型为T)时,由于模板是一个引用类型,因此它被隐式装换为左值引用类型T&,根据推导规则1,模板参数A被推导为T&。这样,在G内部调用F(static_cast(a))时,static_cast(a)等同于static_cast
当传给G一个右值(类型为T)时,由于模板是一个引用类型,因此它被隐式装换为右值引用类型T&&,根据推导规则2,模板参数A被推导为T。这样,在G内部调用F(static_cast(a))时,static_cast(a)等同于static_cast
可见,使用该方案后,左值和右值都能正确地进行转发,并且不会带来其他问题。另外,C++ 11为了方便转发的实现,提供了一个函数模板forward,用于参数的完美转发。使用forward后的代码可简化为:
?
?
?
为了便于进行各种转发方案的比较,下面以表格的形式列出了各自的特性。
?
转发方案非常量左值常量左值非常量右值常量右值修改语言已知问题
?
一、非常量左值引用非常量左值常量左值无法转发常量左值否无法接收非常量右值的参数
二、常量左值引用常量左值常量左值常量左值常量左值否无法将常量左值引用转发给非常量左值引用
三、非常量左值引用 + 常量左值引用非常量左值常量左值常量左值常量左值否重载函数过多,实际编码不可行
四、常量左值引用 + const_cast非常量左值非常量左值非常量左值非常量左值否可修改常量左值和常量右值,不安全
五、非常量左值引用 + 修改的参数推导规则非常量左值常量左值常量左值常量左值是会导致兼容性问题,且不支持移动语义
六、右值引用无法转发无法转发非常量左值常量左值是可修改非常量右值,不安全
七、右值引用 + 修改的参数推导规则非常量左值常量左值非常量右值常量右值是暂无,故简称为完美转发
?
?
?