c++ - 模板中关于引用折叠的右值(&&) 左值(&) 引用绑定(bind)的规则是什么?

标签 c++ templates rvalue lvalue reference-collapsing

考虑这些情况:

int i{};
int& ir{i};

class A{
public:
    int& i;
    A(int&& pi):i(pi){}
};

A a1{i}; // Error // case 1
A a2{int(1)}; // OK // case 2

class B{
public:
    int& i;
    template<typename TYPE>
    B(TYPE&& pi):i(pi){}
};

B b1{i}; // OK // case 3
B b2{int(1)}; //OK // case 4
int& ii{int(12)}; // Error // case 5
int& iii{std::move(int(12))}; // Error // case 6

template<typename TYPE>
class C{
public:
    TYPE& i;
    C(TYPE&& pi):i(pi){}
};

C c1{i}; // Error // case 7
C c2{int(1)}; // OK // case 8
C<int&> c3{i}; // OK // case 9
C<int&> c4{int(1)}; // Error // case 10
int&& iiii{ir}; // Error // case 11

右值不能绑定(bind)到左值,如果我的理解是正确的,TYPE&& 将折叠为 TYPE&&TYPE&。 然而我很难理解这些情况,特别是情况 4。如果情况 4 是正确的,那么这意味着我们有 b2.i 这是一个引用,从临时(右值)初始化。那么为什么情况2、5、6、7是错误的呢?当情况 9 正确时,这意味着 TYPE&&int&&& (我假设)折叠为 int& ,那么 c3. i 是从左值初始化的右值(int&&),而情况 10 和 11 不正确?

我希望有人能够详细解释有关此主题的一般规则以及这些案例。

最佳答案

这里有几种机制在起作用:左值/右值语义、引用折叠、转发引用和 CTAD。我认为解释你列出的案例应该足以形成一个整体。

  1. 右值引用 int&& pi 无法绑定(bind)到左值 i
  2. 右值引用 int&& pi 可以绑定(bind)到右值 int(1)i(pi) 中的 pi 引用内存位置,因此它是一个左值,允许初始化 a2.i。构造后,a2.i 是对 int(1) 的悬空引用。
  3. 转发引用TYPE&& pi可以绑定(bind)到左值iTYPEint&b1.i 指的是 i
  4. 转发引用TYPE&& pi可以绑定(bind)到右值int(1)TYPEintTYPE&& pi 是一个右值引用,类似于情况 2 b2.i 是对 int(1) 的悬空引用。
  5. 左值引用 int& ii 无法绑定(bind)到右值 int(12)
  6. 左值引用 int& iii 无法绑定(bind)到右值 std::move(int(12))

在情况 7-10 中,TYPE&& pi 不是转发引用,因为 TYPEclass C 的模板参数,而不是构造函数的模板参数。 CTAD 在 7-8 中用于推导 TYPE,但不会改变这一点:需要一个右值,只有这样才能将 TYPE 推导为 int >,形成int&& pi

  • TYPE 无法推断。
  • TYPE 被推断为 intc2.i,声明为 int& i;,形成对 int(1) 的悬空引用。
  • TYPE 明确为 int&TYPE&& pi 折叠为 int& piTYPE& i 折叠为 int& ic3.i 指的是 i
  • TYPE&& pi 折叠为 int& pi,左值引用无法绑定(bind)到 int(1)
  • 右值引用 int&& iiii 无法绑定(bind)到左值 ir
  • 还有一个额外的案例,可以使案例 2 和 4 更容易理解:

    int&& rvr = 1;
    int&& rvr2 = rvr;
    

    第一行是正确的,最后一行是错误的。 int&& rvr 是一个右值引用,可以延长临时变量的生命周期。但最后一行提到的 rvr 是一个左值,因此右值引用 int&& rvr2 不能与其绑定(bind)。

    关于c++ - 模板中关于引用折叠的右值(&&) 左值(&) 引用绑定(bind)的规则是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76627864/

    相关文章:

    c++ - 如何构建接收引用参数的基类?

    c++ - 分支定界算法实现

    c++ - Eclipse 无法从由类指针构成的 vector 中解析方法 (C++)

    java - 需要建议 : Processing color image from camera; Android; OpenCV; NDK; C++

    c++ - 获取临时对象的地址

    c++ - c++03 与 11 中的返回值

    c++ - 有没有一种方法可以使引用成为常量 setter/getter ?

    python - 使用多个字典键/值的所有组合格式化字符串

    javascript - 是否有适用于 Adob​​e Air 应用程序的 JavaScript 模板引擎?

    c++ - unique_ptr 参数类型的模板参数推导指南?