此处应用了哪种过载解决规则?

时间:2019-01-24 01:43:55

标签: c++ initializer-list overload-resolution

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

我的目的是使用复制构造函数创建一个新的临时实例, 然后将该对象传递给该方法,以便传递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&&)

请告诉这个可怜的家伙。 谢谢!

1 个答案:

答案 0 :(得分:3)

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

  

[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)考虑了Kdy的构造函数。候选人为Kdy(Kdy&&)Kdy(Kdy const&)

为了选择最好的一个,尝试将{kdy}转换为ctor的参数,然后再次应用(3.9)所选的构造函数为复制ctor。然后将prvalue绑定到DoAction的参数,从这些重载DoAction(Kdy&&)可以更好地匹配。

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