为什么const over值引用在重载分辨率期间优先于const rvalue引用

Ori*_*ent 5 c++ constructor rvalue-reference c++11 c++14

为什么没有歧义?

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
}
Run Code Online (Sandbox Code Playgroud)

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

为了实现这一点,我只是= delete;超载了B const &&C const &&,它除了比赛B &&C &&相应.

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

然后我想:"为什么没有歧义?", - 因为模糊性也应该阻止在上述情况下编译错误的代码.

所以问题是:"为什么对于构造函数调用的混合情况没有歧义?".

How*_*ant 5

tl;博士:这是重新设计的.

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

在这个过程中相当晚,随着越来越多的人开始理解该提议,并且由于C++ 11仍在考虑概念,因此规则被更改,因此左值不能绑定到右值引用.

我个人并不觉得这个变化是必要的,但远远更多的人喜欢变化比不喜欢它,和移动语义的基本功能将工作无论哪种方式.所以这绝对是一个值得做出的妥协,而不是完全没有移动语义.

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