【问题标题】:Why reference collapsing rules work only for templates?为什么引用折叠规则仅适用于模板?
【发布时间】:2018-03-27 19:42:45
【问题描述】:
#include <iostream>

template <typename T> void f1(T&& r1){
    std::cout<<r1;
}

void f2(int&& r2){
    std::cout<<r2;
}

int main() {
    int&& x = 42;
    f1(x); //line 1: No error here. Why?
    f2(x);//line2: Error here. why?
}

我想我明白为什么我们在第 2 行出现错误。变量 x 是对 int 42 的右值引用,并且被视为表达式,x 是 左值。在函数 f2 中,输入 r2 是一个rvalue reference,因此只能绑定到一个rvalue,所以我们有一个错误。

现在,我的问题是,为什么函数 f1 中看似等效的代码可以正常工作?我知道这可能与引用折叠规则有关,即当我们执行 f1(x) 时,我们试图用类型参数 T 为 int && 来实例化 f1,因此输入参数 T&& 是 int&& &&,然后减少到 int &&。换句话说,我们有:

void f1<int &&>(int &&);

这意味着这个实例化与函数 f2 中的完全相同,对吧?那么为什么 f1 有效而 f2 无效呢?

【问题讨论】:

  • T 不是int &amp;&amp;Tint &amp;。折叠到int &amp;。见this

标签: c++11 templates parameter-passing pass-by-reference rvalue-reference


【解决方案1】:

那么为什么第 1 行有效?

在模板参数推导中引入了一个特殊规则以允许完美转发。在模板参数推导的上下文中,T&amp;&amp; 不是右值引用,而是转发引用

如果将 左值 传递给采用 转发引用 的函数模板,则类型参数推导出为 T&amp; 而不是 T。这允许引用折叠发生:T&amp; &amp;&amp; 变为 T&amp;

来自cppreference

如果 P 是对 cv 不合格模板参数的右值引用(所谓的转发引用),并且对应的函数调用参数是左值,则使用对 A 的类型左值引用代替 A 进行推导(注: 这是 std::forward 动作的基础 注意:在类模板实参推导中,类模板的模板形参绝不是转发引用(C++17 起))

template<class T>
int f(T&&);       // P is an rvalue reference to cv-unqualified T (forwarding reference)
template<class T>
int g(const T&&); // P is an rvalue reference to cv-qualified T (not special)

int main()
{
    int i;
    int n1 = f(i); // argument is lvalue: calls f<int&>(int&) (special case)
    int n2 = f(0); // argument is not lvalue: calls f<int>(int&&)

//  int n3 = g(i); // error: deduces to g<int>(const int&&), which
                   // cannot bind an rvalue reference to an lvalue
}

在第 2 行中,没有进行模板参数推导 - f2 采用 rvalue 引用,并将拒绝任何不会绑定到它的东西。 左值不绑定到右值引用

【讨论】:

  • 让我快速回顾一下我做错了什么。当我们尝试推导模板类型参数 T 时,我们应该将输入视为一个表达式,即使它也可能是一个变量。作为变量,x 具有 int&& 类型(即,右值引用),但作为表达式,x 具有 int 类型并且是左值。现在,根据你刚才提到的特殊规则,当我们调用f1(x)时,编译器将T的类型推导出为int&,而不是int(也不是 int&&)。最后,基于引用折叠规则,我们将 int& && 简化为 int&。这次我说对了吗?
  • @ivy:对我来说听起来是正确的。这是int&amp; 推论的经验证明:wandbox.org/permlink/vIEe4WtqkVtMRtlF
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-05
  • 2010-11-29
  • 1970-01-01
  • 2017-11-16
相关资源
最近更新 更多