C++ c++;:临时工的特殊行为

C++ c++;:临时工的特殊行为,c++,move,temporary,C++,Move,Temporary,在下面的代码中,为什么第一个调用解析为catchClass(aClass&),并在第二个调用catchClass(const aClassCatcher&) #包括 使用名称空间std; 类aClassCatcher{}; 类aClass{ 公众: 运算符aClassCatcher(){ 返回aClassCatcher(); } }; void catchClass(aClass&){ cout首先,需要注意的是,您观察到的行为与移动语义无关,也与是否存在移动构造函数无关。您可以在C++03编译

在下面的代码中,为什么第一个调用解析为
catchClass(aClass&)
,并在第二个调用
catchClass(const aClassCatcher&)

#包括
使用名称空间std;
类aClassCatcher{};
类aClass{
公众:
运算符aClassCatcher(){
返回aClassCatcher();
}
};
void catchClass(aClass&){

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

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

如果您使用微软的VC编译器,那听起来可能很奇怪。原因是MSVC有一个非标准的扩展,允许绑定值将引用值转换为非->代码> const 。这是IMO的一个坏扩展,而这不是标准C++的工作方式。 这就是说,当你提供一个临时变量,它是一个右值时,编译器没有机会选择一个重载,这个重载将左值引用到

const
。这个重载将左值引用到non-
const
是不可行的,因为我以前写过

现在在您的例子中,第二个重载是可行的,因为有一个用户定义的从
aClass
aClassCatcher
的转换。该转换将返回一个类型为
aClassCatcher
的临时变量,对
const
的左值引用可以绑定到临时变量。因此,选择第二个重载


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

因为临时变量不能绑定到非常量左值引用。嘿…我刚刚将aClass_uuuu重命名为aClassCatcher以避免混淆…这里有点新。。。我将为后代编辑您的答案…:-)谢谢…我明白您所说的糟糕的microsoft扩展的意思…因为,当我注释掉
catchClass(const aClassCatcher&)
时,两个调用都解析为
catchClass(aClass&)
@user1055604:的确,这很糟糕;)我将编辑答案,使其与您的问题的编辑相匹配。所说的非标准扩展是……谢谢您的回答……只是确定一下,但在第二个最后一段的第二个最后陈述中……您的意思是
对非常量的左值引用可以绑定到临时变量。因此,您的第二个副词是选择d。
还是将其
左值引用到const
#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&)

}