我对以下代码感到困惑:
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
?
答案 0 :(得分:10)
来电f()
被解释为(*this).f()
。取消引用指针的结果总是左值,因此*this
是左值,并且调用左值限定函数。
这种行为甚至有意义,至少对我而言。大多数情况下,rvalue表达式引用的对象将在full-expression(临时)的末尾或当前作用域的末尾被销毁(我们选择std::move
的自动局部变量)。但是当你在里面成员函数时,这些都不是真的,所以对象不应该把它自己当作右值,可以这么说。这也是为什么将右值参考函数参数的名称作为函数中左值的有意义的原因。
如果您想要调用rvalue-qualified f
,可以执行以下操作:
std::move(*this).f();
答案 1 :(得分:3)
这是因为解除引用 1 this
总是会产生一个左值,而不管它是指向一个临时值对象与否。
所以当你这样写:
f();
它实际上意味着:
this->f(); //or (*this).f()
//either way 'this' is getting dereferenced here
因此,从f()
调用为 lvalue 编写的g()
的重载 - 并且相应地应用了const-correctness。
希望有所帮助。
1。请注意this
是一个prvalue;只有在解除引用后才会产生左值。功能
答案 2 :(得分:2)
ref-qualifiers 影响隐式对象参数,§13.3.1/ 4:
对于非静态成员函数,隐式对象的类型 参数是
对于声明的函数,
- “对 cv
X
的左值引用” 没有引用限定符或使用&
引用限定符- “右值 对于使用
X
声明的函数,引用 cv&&
“ ref-qualifier其中
X
是该函数所属的类,而 cv 是 成员函数声明的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,关于标准转换的最后一个要点)。
答案 3 :(得分:1)
好吧,对于f()
,正确的限定词始终为lvalue reference
,因为您在this
上使用它。您的所有f
来电都不是this->f()
,而this
始终是lvalue
。对于外部世界而言,rvalue
this
对象是内部对象的左值是无关紧要的。