我想知道在这里应用了哪种重载方法解析规则。
我的目的是使用复制构造函数创建一个新的临时实例,
然后将该对象传递给方法,以便传递r值引用。
并且有重载的方法接受l值,r值,因此我期望r值重载方法将被调用,但事实并非如此。
class Kdy {
public:
Kdy() {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Kdy(Kdy&&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Kdy(const Kdy&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void DoAction(const Kdy&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void DoAction(Kdy&&) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
}; // Kdy
int main() {
Kdy kdy1;
Kdy kdy2;
// DoAction(const Kdy&), Why??
// kdy1.DoAction(Kdy(kdy2))
kdy1.DoAction({kdy2});
// Then why this works?
// After copy-ctor, DoAction(Kdy&&) was invoked.
kdy1.DoAction({ {kdy2} });
// Then why this dosen't compile?
// Since { {kdy2} } becomes Kdy&&
// { { {kdy2} } } should be Kdy(Kdy&&)
// kdy1.DoAction({ { {kdy2} } });
return 0;
}
我已多次阅读过载引用文档,
但对我来说一半清楚
https://en.cppreference.com/w/cpp/language/overload_resolution
在收集了一组候选方法之后,
编译器根据其匹配优先级来决定哪种方法最匹配。
因此,很明显,如果有一些方法接受
std::initializer_list<Kdy>
作为参数,则选择这些方法。 (我已经测试过)那时仍然令人困惑
如果精确的签名匹配失败,
在此情况下应用了哪种分辨率重载规则?
是什么让编译器认为匹配
{kdy2}
最适合const Kdy&
而不是Kdy&&
?另外,为什么
{ { { kdy2 } } }
无法解释为Kdy(Kdy&&)
?请告诉这个可怜的家伙。
谢谢!
最佳答案
让我们以标准的以下部分作为引用:
(3.9)节解释了为什么DoAction({kdy2})
选择重载DoAction(const Kdy&)
。初始化列表的单个元素是Kdy
类型的左值,从DoAction
的两个重载中,只有一个可以绑定(bind)到左值。一个被选中。
在DoAction({ {kdy2} })
中,初始化程序没有单个类型为Kdy
的元素,不使用(3.9),并且为{{kdy2}}
引入了prvalue。 (3.7)考虑了Kdy
的构造函数。候选人是Kdy(Kdy&&)
和Kdy(Kdy const&)
。
为了选择最好的一个,尝试将{kdy}
转换为ctor的参数,然后再次应用(3.9)所选的构造函数为复制ctor。然后将prvalue绑定(bind)到DoAction
的参数,并且从这些重载DoAction(Kdy&&)
中可以找到更好的匹配。
对于DoAction({ { {kdy2} } })
,尝试在第二种情况下进行尝试,但是当尝试将{{kdy2}}
转换为构造函数的参数时,它会失败,因为初始化列表没有单个类型Kdy
的元素,并且(3.7)不适用。