我编写了这个简单的测试来根据
this
是右值还是左值进行重载。最初的版本有额外的情况,但我将其减少到令我困惑的情况。
#include <iostream>
struct A {
int pp=0;
A(int p) : pp(p) {}
A &prop(int nn) & {pp=nn; return *this;}
A &&prop(int nn) && {pp=nn; return std::move(*this);}
};
struct B {
B(const A &aa) {std::cout << "COPY: " << aa.pp << std::endl;}
B(A &&aa) {std::cout << "MOVE: " << aa.pp << std::endl;}
};
int main() {
A aa(99);
B b4(aa.prop(33).prop(4)); // 4 COPY
std::cout << "4 == " << aa.pp << std::endl;
return 0;
}
输出是我所期望的
COPY: 4
4 == 4
到目前为止,一切都很好。然后我修改了
A
以使用推导this
的方法:
struct A {
int pp=0;
A(int p) : pp(p) {}
template <typename self> A prop(this self &&me, int nn) {
me.pp=nn;
return me;
}
};
我期望得到相同的结果,但我没有:
MOVE: 4
4 == 33
为什么第二个版本要调用move方法?
即使它调用了 move 方法,我仍然希望看到
nn
设置为 4 而不是 33。
发生什么事了?
在“推导这个”的情况下,你总是按值返回一个
A
对象,所以:
aa.prop(33).prop(4)
将
33
分配给 aa.pp
,然后 prop(4)
部分将 4
分配给刚刚返回的 pp
的 copy 的 aa
,从而将 aa.pp
保留为 33
。
您需要做的是返回
A&
或 A&&
引用,具体取决于 this
的推导方式。 为此,您可以使用 decltype(auto)
来推断返回对象的值类别并返回正确的类型。