std::move(*this)是一个很好的模式吗?

Is std::move(*this) a good pattern?

本文关键字:很好 一个 模式 move this std      更新时间:2023-10-16

为了使这段带有 C++11 引用限定符的代码按预期工作,我必须引入一个听起来不正确的std::move(*this)

#include<iostream>
struct A{
    void gun() const&{std::cout << "gun const&" << std::endl;}
    void gun() &&{std::cout << "gun&&" << std::endl;}
    void fun() const&{gun();}
    void fun() &&{std::move(*this).gun();} // <-- is this correct? or is there a better option
};
int main(){
    A a; a.fun(); // prints gun const&
    A().fun(); // prints gun&&
}

听起来有些不对劲。std::move有必要吗?这是推荐的用途吗?目前,如果我不使用它,我会在这两种情况下都得到gun const&,这不是预期的结果。

(似乎*this始终是隐式和左值引用,这是有道理的,但这是唯一的逃避方法使用move(

经过clang 3.4gcc 4.8.3测试。

<小时 />

编辑:这是我从@hvd答案中理解的:

  1. std::move(*this)在语法和概念上是正确的

  2. 但是,如果gun不是所需接口的一部分,则没有理由重载它的lv-ref和rv-ref版本。两个具有不同名称的函数可以完成相同的工作。毕竟,引用限定符在接口级别很重要,这通常只是公共部分。

struct A{
private:
    void gun() const{std::cout << "gun const&" << std::endl;}
    void gun_rv(){std::cout << "gun called from fun&&" << std::endl;}
public:
    void fun() const&{gun();}
    void fun() &&{gun_rv();} // no need for `std::move(*this)`.
};

但同样,如果gun是(通用(接口的一部分,那么std::move(*this)是必要的,但只有这样。而且,即使gun不是界面的一部分,也不将函数gun拆分为两个不同名称的函数具有可读性优势,这样做的成本是,嗯......,std::move(*this)

编辑2:回想起来,这类似于同一函数const和无const过载的C++98情况。在某些情况下,使用 const_cast(另一种形式的强制转换(来不重复代码并让两个函数具有相同的名称 (https://stackoverflow.com/a/124209/225186( 是有意义的。...尽管在更复杂的情况下,使用辅助私有函数来委托接口函数的正确行为是有意义的。

是的,无论如何调用成员函数,*this始终是左值,因此如果您希望编译器将其视为右值,则需要使用 std::move 或等效值。考虑到这个类,它必须是:

struct A {
  void gun() &; // leaves object usable
  void gun() &&; // makes object unusable
  void fun() && {
    gun();
    gun();
  }
};

*this设为右值意味着fun第一次调用gun会使对象无法使用。然后,第二个调用将失败,可能很严重。这不是应该隐含发生的事情。

这也是为什么在void f(T&& t) 中,t是一个左值的原因。在这方面,*this与任何参考函数参数没有什么不同。