C++ 模板实参推断和引用折叠

两个例外规则

假定 i 是一个 int 对象,我们可能认为像 f3(i) 这样的调用是不合法的。毕竟,i是一个左值,而通常我们不能将一个右值引用绑定到一个左值上。但是,C++语言在正常绑定规则之外定义了两个例外规则,允许这种绑定。这两个例外规则是move 这种标准库设施正确工作的基础。

第一个例外规则影响右值引用参数的推断如何进行。当我们将一个左值(如i)传递给函数的右值引用参数,且此右值引用指向模板类型参数(如T&&)时,编译器推断模板类型参数为实参的左值引用类型。因此,当我们调用f3(i)时,编译器推断T的类型为int&,而非int。

T被推断为int&看起来好像意味着f3的函数参数应该是一个类型int&的右值引用。通常,我们不能(直接)定义一个引用的引用(参见2.3.1节,第46页)。但是,通过类型别名(参见2.5.1节,第60页)或通过模板类型参数间接定义是可以的。

在这种情况下,我们可以使用第二个例外绑定规则:如果我们间接创建一个引用的引用,则这些引用形成了“折叠”。在所有情况下(除了一个例外),引用会折叠成一个普通的左值引用类型。在新标准中,折叠规则扩展到右值引用。只在一种特殊情况下引用会折叠成右值引用:右值引用的右值引用。即,对于一个给定类型 X:

  • X& &X& &&X&& &都折叠成类型X&
  • 类型X&& &&折叠成X&&

Note:
引用折叠只能应用于间接创建的引用的引用,如类型别名或模板参数。

两个重要结果

  • 如果一个函数参数是一个指向模板类型参数的右值引用(如,T&&),则它可以被绑定到一个左值;且
  • 如果实参是一个左值,则推断出的模板实参类型将是一个左值引用,且函数参数将被实例化为一个(普通)左值引用参数(T&)

这两个规则暗示,我们可以将任意类型的实参传递给T&&类型的函数参数。

Note:
如果一个函数参数是指向模板参数类型的右值引用(如,T&&),则可以传递给它任意类型的实参。如果将一个左值传递给这样的参数,则函数参数被实例化为一个普通的左值引用(T&)。

std::move

从一个左值 static_cast 到一个右值引用是允许的

通常情况下,static_cast 只能用于其他合法的类型转换(参见 4.11.3 节,第 145页)。但是,这里又有一条针对右值引用特许规则:虽然不能 隐式地将一个左值转换为右值引用,但我们可以用static_cast显式地将一个左值转换为一个右值引用

std::forward 转发

类似move,forward定义在头文件utility中。与move不同,forward必须通过显式模板实参来调用(参见16.2.2节,第603页)。forward返回该显式实参类型的右值引用。即,forward<T>的返回类型是T&&

示例:

template <typename F, typename Tl, typename 2>
void flip(F f, Tl &&tl, T2 &&t2)
{
     f(std::forward<T2>(t2), std::forward<T1>(t1));
}




源自:《C++ Primer》 P608

posted @   double64  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2021-11-08 C# SerialPort 串口的基本使用
2021-11-08 WPF DataTemplate 数据模板放在单独的 XAML 文件中以静态资源的 Source 路径进行访问
点击右上角即可分享
微信分享提示