为什么常量左值引用在重载解析期间优先于常量右值引用

Why const lvalue reference has priority over const rvalue reference during overloading resolution

本文关键字:引用 常量 优先于 重载 为什么      更新时间:2023-10-16

为什么没有歧义?

struct B {};
struct C {};
struct A
{
A(B const &, C const &) {}
A(B const &&, C const &&) = delete;
#if 0
A(B const &, C const &&) = delete;
A(B const &&, C const &) = delete;
#endif
};
B const b() { return {}; } // const result type may make sense
C const c() { return {}; } // for some user-defined types
int main()
{
A a0{B{}, C{}}; // I want to prohibit this
A a1{b(), c()}; // and this cases
B const bb{};
C const cc{};
A a2{b(), cc}; // But surely I also want to prohibit this
A a3{bb, c()}; // and this cases to compile
}

在这里,我想将对BC实例的 lvalue const 引用存储到A的实例中。当然,我想确保引用对象的生存期克服A实例的生存期。

为了实现这一点,我只是= delete;B const &&C const &&的重载,此外,它还相应地匹配B &&C &&

上述方法非常适合转换构造函数(即一元构造函数)。但事实证明,对于更高的arity,我必须明确= delete;所有组合上可能的组合,这些组合包含感兴趣参数的常量右值参考版本(即#if 1)。

然后我想:"为什么没有歧义?"——因为歧义也应该防止在上述情况下编译错误的代码。

所以问题是:"为什么构造函数调用的混合大小写没有歧义?

tl;大卫:它是这样重新设计的。

在最初的移动提案下,您的代码将是模棱两可的。 根据该建议,左值可以绑定到右值引用,但如果重载集中存在左值引用,则更喜欢左值引用。

在这个过程的后期,随着越来越多的人开始理解该提案,并且由于C++11的概念仍在考虑中,规则发生了变化,以便左值无法绑定到右值引用。

我个人认为这种更改没有必要,但喜欢这种更改的人比不喜欢它的人要多得多,并且移动语义的基本功能可以正常工作。 所以这绝对是一个值得做出的妥协,而不是根本没有移动语义。

由于更改了 lvalues 无法绑定到右值引用,如果任一参数是 lvalue,则A(B const &&, C const &&)不是重载解析集的一部分。 但是,如果其中一个(或两个)参数都是左值,则A(B const &, C const &)保留在重载集中。