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

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

为什么没有歧义?

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 实例的左值常量引用存储到 A 的实例中。当然,我想确保引用对象的生命周期超过 A 实例的生命周期。

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

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

然后我想:"Why there is no an ambiguity?",——因为歧义也应该可以防止在上面的情况下编译错误的代码。

所以问题是:"Why there is no ambiguity for mixed case of constructor's invocation?".

tl;dr:它是 re 那样设计的。

the original move proposal 下,您的代码会含糊不清。根据该提案,左值 可以 绑定到右值引用,但如果它存在于重载集中,则更喜欢左值引用。

过程相当晚,因为越来越多的人开始理解该提案,并且由于 C++11 的概念仍在考虑中,the rules were changed so that lvalues could not bind to rvalue references

我个人认为没有必要进行此更改,但是 喜欢此更改的人多于不喜欢它的人,移动语义的基本功能将以任何一种方式发挥作用。所以这绝对是一个值得做出的妥协,而不是根本没有移动语义。

随着左值不能绑定到右值引用的变化,如果 任一 参数是左值,A(B const &&, C const &&) 将不是重载决议集的一部分。但是,如果其中一个(或两个)参数是左值,A(B const &, C const &) 将保留在重载集中。