3

在下面的代码中,为什么第一次调用解析为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&)

}

如果您想知道我是从哪里想到这个的,我正在尝试理解Dobb 的一篇文章中描述的移动构造函数。

4

1 回答 1

5

首先,重要的是要注意您观察到的行为与移动语义无关,也与移动构造函数的存在或不存在无关。您可以在 C++03 编译器上运行您的示例并观察完全相同的行为。

您观察到的行为的解释是,对非const( aClass&) 的左值引用只能绑定到左值,而对const( const aClassCatcher&) 的左值引用可以同时绑定到左值和右值(但不允许修改它们绑定的对象,因为它们是对const) 的引用。

如果您正在使用 Microsoft 的 VC 编译器,您可能会觉得这很奇怪。原因是 MSVC 有一个非标准扩展,它允许将右值绑定到对非的左值引用const。这是 IMO 一个糟糕的扩展,而标准 C++ 不是这样工作的。

现在这就是说,当您提供一个临时值(即右值)时,编译器没有机会,只能选择接受左值引用的重载const。由于我之前写的内容,对 non- 进行左值引用的重载const根本不可行。

现在在您的情况下,第二个重载是可行的,因为有一个用户定义的从aClassto转换aClassCatcher。该转换将返回一个临时类型aClassCatcher,并且左值引用const可以绑定到临时对象。因此,您的第二个重载被选中。

另一方面,当您提供左值时,两种重载都是可行的,但const首选接受对 non- 的左值引用的重载,因为不需要转换。

于 2013-06-09T09:57:05.930 回答