【发布时间】:2014-10-09 16:16:08
【问题描述】:
为了使这个带有 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.4 和gcc 4.8.3 测试。
编辑:这是我从@hvd 的回答中了解到的:
-
std::move(*this)在语法和概念上都是正确的 -
但是,如果
gun不是所需接口的一部分,则没有理由重载它的 lv-ref 和 rv-ref 版本。两个不同名字的函数可以做同样的工作。毕竟 ref-qualifiers 在接口级别很重要,这通常只是公共部分。
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:回想起来,这类似于 C++98 中 const 和 no-const 重载同一函数的情况。在某些情况中,使用const_cast(另一种形式的强制转换)来避免重复代码并让两个函数具有相同的名称(https://stackoverflow.com/a/124209/225186)是有意义的。
...虽然在更复杂的情况下,使用辅助私有函数来委托接口函数的正确行为是有意义的。
【问题讨论】:
-
如果你不想用
std::move,那static_cast<A&&>(*this).gun()呢? -
@yohjp,或者
std::forward<A&&>(*this).gun()。 -
我建议创建一个名为
rvalue()的成员函数,该函数将*this作为右值返回。然后你可以拨打this->rvalue()->...。 -
@Mehrdad,会不会是这样写的函数
auto rvalue()->decltype(std::move(*this)){return std::move(*this);}?
标签: c++ c++11 this move-semantics lvalue