Why const lvalue reference takes precedence over rvalue constant reference when permission is overloaded

Why is there no ambiguity?

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 } 

Here I want to save the lvalue const references for instances of B and C to instance A Of course, I want to make sure that the lifetime of referenced objects exceeds the lifetime of instance A

To achieve this, I simply overloaded = delete; for B const && and C const && , which also corresponds to B && and C && respectively.

The above approach works fine for conversion constructors (i.e. unary). But it turns out that for higher phenomena I must explicitly = delete; use all combinatorially possible combinations that include constant reference versions of the parameters of interest (i.e. #if 1 ).

Then I think, “Why is there no ambiguity?” Because ambiguity should also prevent compilation of the wrong code in the above case.

So the question is: “Why is there no ambiguity for the mixed case of calling the constructor?”.

+5
source share
1 answer

tl; dr: It was re- designed this way.

In the original move sentence, your code will be mixed. As part of this proposal, lvalues ​​can bind to rvalue links, but prefer the lvalue link if it exists in the overload set.

Pretty late, as more people began to understand this proposal, and as concepts were still being considered for C ++ 11, the rules were changed so that lvalues ​​could not bind to rvalue links .

I personally did not feel that this change was necessary, but many more people liked the change than did not like it, and the basic functionality of the movement semantics will work anyway. Thus, it was definitely a compromise worth making rather than getting the semantics of movement at all.

With a change that lvalues ​​cannot bind to rvalue references, A(B const &&, C const &&) not part of overload resolution if any argument is an lvalue. However, A(B const &, C const &) remains in the overload set if both (or both) arguments are equal to lvalues.

+5
source

Source: https://habr.com/ru/post/1261785/


All Articles