转发引用:引用参数来源

Forwarding references: reference parameter origin

关于转发引用(又名通用引用)的整个前提是,这个函数:

template<typename T>
void f(T&&) { }

可能导致模板参数为 int&int,具体取决于您是以 int a{}; f(a) 还是 f(5) 为例调用它。但我认为这已经太过分了。因为当我有一个像

这样的函数时
template<typename T>
auto g(T) -> void {}

然后它总是将模板参数解析为 int,无论我如何调用它。而且尽管 auto h(int&) -> void {} 是完全合法的。

那么有什么规则允许 f 的模板参数作为参考,而不是 g 的模板参数?

对于函数参数具有 T&&(cv-unqualified)形式的情况,模板参数推导规则中有一个特定的例外,其中 T 是模板参数。这种特殊情况如被称为 转发参考.

的问题所示

对于转发引用,如果函数参数是左值,则为 T 推导左值引用,而通常不会推导任何引用类型。

您可以通过尝试使用例如const T&& 而不是 T&&,特殊规则不适用。在任何情况下,它都会为 T 推断出非引用类型,尽管函数调用可能无法进行。

你可以阅读 Effective modern C++ 的答案,第一章,它说,我们可以认为函数模板看起来像这样:

    template<typename T>
    void f(paramType param);

TparamType 通常不同,paramType 通常包含像 const 这样的修饰符或像 const T&

这样的引用限定符

他在三个案例中谈到了这一点

  1. paramType 是指针或引用类型
  2. paramType 是通用引用
  3. paramType 既不是指针也不是引用

你的第一个函数是case2,因为需要推导类型,&&这里是通用引用,你的第二个函数是case3,paramType既不是指针也不是引用

During type deduction for a template parameter that is a universal reference, lvalues and rvalues of the same type are deduced to have slightly different types.

  • 类型 T 的左值被推导为类型 T&
  • 类型 T 的右值被推导为类型 T

所以f(a)你得到了f(int& && param) 然后是“引用折叠”规则

  • 右值引用到右值引用成为右值引用
  • 对引用的所有其他引用都折叠成左值引用

所以你得到了f(int& param)