这里应用了哪条过载解决规则

Which overload resolution rule applied here?

本文关键字:解决 规则 应用 这里      更新时间:2023-10-16

我想知道这里应用了哪种重载方法解析规则。

我的目的是使用复制构造函数创建一个新的临时实例,然后将该对象传递给方法,从而传递r值引用。

还有一些重载方法可以接受l-value、r-value,所以我希望会调用r-value重载方法,但事实并非如此。

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}Kdy&&更适合const Kdy&

为什么{ { { kdy2 } } }不能解释为Kdy(Kdy&&)

请揭露这个可怜的家伙。非常感谢。

让我们以标准的以下部分为参考:

[dcl.init.list]

  • (3.7)否则,如果T是类类型,则考虑构造函数。枚举适用的构造函数,并通过重载解析选择最佳构造函数
  • (3.9)否则,如果初始值设定项列表具有E类型的单个元素,并且T不是引用类型,或者其引用类型是与E相关的引用,则从该元素初始化对象或引用

第(3.9)节解释了DoAction({kdy2})选择过载DoAction(const Kdy&)的原因。初始值设定项列表的单个元素是类型为Kdy的左值,并且从DoAction的两个重载中,只有一个可以绑定到左值;选择的一个。

DoAction({ {kdy2} })中,初始化器没有Kdy类型的单个元素,不使用(3.9),并且为{{kdy2}}引入了prvalue。通过(3.7)考虑了CCD_ 14的构造函数。候选为Kdy(Kdy&&)Kdy(Kdy const&)

为了选择最好的构造函数,尝试将{kdy}转换为ctor的参数,并再次应用(3.9)所选的构造函数是复制ctor。然后将pr值绑定到CCD_ 18的参数,并且从这些过载CCD_。

对于DoAction({ { {kdy2} } }),尝试与第二种情况相同,但当尝试将{{kdy2}}转换为构造函数的参数时,它失败了,因为初始化器列表没有Kdy类型的单个元素,并且(3.7)不适用。