问题 function &&限定符行为


我对以下代码感到困惑:

struct test {
  void f() & {
    std::cout << "&" << std::endl;
  }
  void f() const& {
    std::cout << "const&" << std::endl;
  }
  void f() && {
    std::cout << "&&" << std::endl;
  }
  void f() const&& {
    std::cout << "const&&" << std::endl;
  }

  void g() & {
    std::cout << "& -> ";
    f();
  }
  void g() const& {
    std::cout << "const& -> " ;
    f();
  }
  void g() && {
    std::cout << "&& -> ";
    f();
  }
  void g() const&& {
    std::cout << "const&& -> ";
    f();
  }

  test() {} //allow default const construction
};

int main(int, char**) {
    test value;
    const test constant;

    value.g();
    constant.g();

    std::move(value).g();
    std::move(constant).g();
}

当我用clang 3.5编译时,我得到了这个输出:

& -> &
const& -> const&
&& -> &
const&& -> const&

为什么r值限定符会被丢弃?有没有办法打电话 f 从 g 有合适的资格赛?


4548
2018-05-07 06:54


起源



答案:


电话 f() 被解释为 (*this).f()。取消引用指针的结果总是左值,所以 *this 是左值,并且调用左值限定函数。

这种行为甚至有意义,至少对我而言。大多数情况下,rvalue表达式引用的对象将在full-expression(临时)的末尾或当前作用域的末尾被销毁(我们选择的自动局部变量) std::move)。但是当你的时候  一个成员函数,这些都不是真的,所以对象不应该把它自己当作右值,可以这么说。这也是为什么将右值参考函数参数的名称作为函数中的左值是有意义的。

如果你想要rvalue合格 f 要打电话,你可以这样做:

std::move(*this).f();

10
2018-05-07 07:19



你好像在想 解除引用语法 必须的形式 *pointer不是 pointer->。嗯,事实是两者都是 提领。 - Nawaz
@Nawaz我只是想让它更清楚。 - Brian


答案:


电话 f() 被解释为 (*this).f()。取消引用指针的结果总是左值,所以 *this 是左值,并且调用左值限定函数。

这种行为甚至有意义,至少对我而言。大多数情况下,rvalue表达式引用的对象将在full-expression(临时)的末尾或当前作用域的末尾被销毁(我们选择的自动局部变量) std::move)。但是当你的时候  一个成员函数,这些都不是真的,所以对象不应该把它自己当作右值,可以这么说。这也是为什么将右值参考函数参数的名称作为函数中的左值是有意义的。

如果你想要rvalue合格 f 要打电话,你可以这样做:

std::move(*this).f();

10
2018-05-07 07:19



你好像在想 解除引用语法 必须的形式 *pointer不是 pointer->。嗯,事实是两者都是 提领。 - Nawaz
@Nawaz我只是想让它更清楚。 - Brian


这是因为 提领1  this  总是 产生左值,而不管它是否指向临时物体。

所以当你写这个:

f();

它实际上意味着:

this->f(); //or (*this).f()
           //either way 'this' is getting dereferenced here

所以过载了 f() 这是写的 左值 被调用 g()  - 并且相应地应用const-correctness。

希望有所帮助。


请注意 this 是一个prvalue;只有在解除引用后才产生左值。


3
2018-05-07 07:00





REF-预选赛 影响隐式对象参数,§13.3.1/ 4:

对于非静态成员函数,隐式对象的类型   参数是

  • “左值参考 简历  X“对于声明的函数   没有 REF-预选赛 或与 &  REF-预选赛 
  • “右值   参考 简历  X“用于声明的函数 && REF-预选赛 

哪里 X 是函数所属的类 简历 是   成员函数声明的cv资格。

粗略地说,重载分辨率是在对象参数转换的对象参数上执行的,就像任何其他参数 - >参数转换一样。
然而, f() 变成了 (*this).f() (§9.3.1/ 3),和 *this 是一个左值。 §5.3.1/ 1:

一元 * 运营商执行间接:[...] 结果是左值引用表达式指向的对象或函数

因此,超载 f 随着 & 限定符是首选 - 实际上,rvalue重载完全被忽略,因为rvalue对象引用的初始值必须是rvalues(§8.5.3/ 5中的最后一个要点)。此外,在重载分辨率中,非const引用优于常量引用(第13.3.3.2 / 3节,关于标准转换的最后一个要点)。


2
2018-05-07 07:11





好吧,对 f()合适的资格赛总是如此 lvalue reference 因为你使用它 this。你的全部 f 电话只不过是 this->f() 和 this 总是 lvalue。对于外部世界来说,对象是无关紧要的 rvalue  this 是对象内部的左值。


1
2018-05-07 06:59