On Tue, Oct 11, 2022 at 12:25 PM Lénárd Szolnoki via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On 11 October 2022 17:08:59 BST, Thiago Macieira via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
>On Tuesday, 11 October 2022 04:30:52 PDT Ville Voutilainen via Std-Proposals wrote:
>> void f(int&&) { puts("int"); }
>> void f(double&&) { puts("double"); }
>>
>> so
>>
>> int i = 1;
>> f(i);
>>
>> prints "double", because it can't call void f(int&&). Instead, it'll
>> convert the int to double,
>> and call void f(double&&).
>
>But why can't it convert int to int and then call the int&& overload?

Right. This could replace "pass by value then move" and save a move when a user passes an xvalue. Now it requires an overload or a template to achieve the same thing.
[...]
It would be nice to have tooling to be able to have non-template `void foo(??create_obj_if_necessary?? T&&)` (not proposing this syntax and name) that would have the behavior you describe. I tried to have library solution for it, but it doesn't seem possible.

I think you're forgetting the obvious (and C++-beginner-track) answer: pass by value!
   void foo(int t);
is exactly the thing you're looking for: it copies if an lvalue is passed, moves if an rvalue is passed, permits modification of the parameter's value inside the function, and doesn't require any crazy overloads or templates.

The current behavior (rvalue references don't bind to lvalues, lvalue references don't bind to rvalues, const T& binds to everything) is easy to teach in practice.

–Arthur