在下面的代码中,为什么第一个调用解析为 catchClass(aClass&)
并在第二个调用中将临时对象作为参数提供给 catchClass(const aClassCatcher&)
#include <iostream>
using namespace std;
class aClassCatcher{};
class aClass{
public:
operator aClassCatcher(){
return aClassCatcher();
}
};
void catchClass(aClass&){
cout << __FUNCSIG__ << endl;
}
void catchClass(const aClassCatcher&){
cout << __FUNCSIG__ << endl;
}
int main()
{
aClass aC;
catchClass(aC); // calls catchClass(aClass&)
catchClass(aClass()); // calls catchClass(const aClassCatcher&)
}
如果您想知道我是从哪里得到这个的,我正在尝试理解 move 构造函数,如 Dobb's. 上的一篇文章所述。
最佳答案
首先,请务必注意,您观察到的行为与 move 语义无关,也与 move 构造函数的存在与否无关。您可以在 C++03 编译器上运行示例并观察完全相同的行为。
对您观察到的行为的解释是,对非 const
(aClass&
) 的左值引用只能绑定(bind)到左值,而对 const 的左值引用
(const aClassCatcher&
) 可以绑定(bind)到左值和右值(但不允许修改它们绑定(bind)到的对象,因为它们是对 const
的引用) .
如果您正在使用 Microsoft 的 VC 编译器,您可能会觉得这很奇怪。原因是 MSVC 有一个非标准扩展,它允许将右值绑定(bind)到对非 const
的左值引用。这是 IMO 的一个坏扩展,标准 C++ 不是这样工作的。
现在这就是说,当您提供一个临时值(右值)时,编译器别无选择,只能选择采用对 const
的左值引用的重载。重载对非 const
进行左值引用是不可行的,因为我之前写过。
现在在您的情况下,第二个重载是可行的,因为存在从 aClass
到 aClassCatcher
的用户定义转换。该转换将返回 aClassCatcher
类型的临时对象,并且对 const
的左值引用可以绑定(bind)到临时对象。因此,您的第二个过载被选中。
另一方面,当您提供左值时,两种重载都是可行的,但首选接受对非 const
的左值引用的重载,因为不需要转换。
关于c++:临时对象的特殊行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17008434/