c ++:临时的特殊行为

时间:2013-06-09 09:54:54

标签: c++ move temporary

在下面的代码中,为什么第一个调用解析为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's.

中的文章所述

1 个答案:

答案 0 :(得分:5)

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

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

如果您正在使用Microsoft的VC编译器,那可能听起来很奇怪。原因是MSVC具有非标准扩展,允许绑定rvalues以对非const的引用进行左值化。这是IMO的一个扩展,而这不是标准C ++的工作方式。

现在这样说,当你提供一个临时值,这是一个rvalue时,编译器没有机会选择带有左值引用const的重载。由于我之前所写的内容,对非const进行左值引用的重载根本不可行。

现在,在您的情况下,第二次重载是可行的,因为存在从constaClass的用户定义转换。该转换将返回aClassCatcher类型的临时值,aClassCatcher的左值引用可以绑定到临时值。因此,选择了第二个重载。

另一方面,当你提供一个左值时,两个重载都是可行的,但接受非const左值引用的那个是首选,因为不需要转换。