Bug 12672 – make "ref" a better match than "auto_ref" (especially for variadic arguments)

Status
RESOLVED
Resolution
WONTFIX
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2014-04-28T10:03:07Z
Last change time
2022-08-22T15:31:08Z
Assigned to
No Owner
Creator
monarchdodra

Comments

Comment #0 by monarchdodra — 2014-04-28T10:03:07Z
Whenever you use "auto ref", the compiler will *completely* create different functions depending on the ref-ness of the parameters. This is necessary, since the compiler can use exploit the pass by value/pass by ref to potentially move things around without postblit. It also allows explicit things such as what is in Tuple: void opAssign(R)(auto ref R rhs) { static if (!__traits(isRef, rhs)) // Use swap-and-destroy to optimize rvalue assignment swap!(Tuple!Types)(this, rhs); else // Do not swap; opAssign should be called on the fields. field[] = rhs.field[]; } Having two template instances is fine for trivial functions, but for long functions that actually *do* things, it is better to use an "ref"/"value" overload. EG: void foo(Arg)(Arg arg) { foo(arg); } void foo(Arg)(ref Arg arg) { //longContent } This is *particularly* relevant for functions that take variadic arguments, since the compiler could potentially generate "up to" 2^^N templates, that all do the same thing (!) The issue is that when one does: void foo(Args...)(Args args) { foo(args); } void foo(Args...)(ref Args args) { //longContent } The issue with this approach though is that if *1* of the passed arguments is not a reference, the they will *all* be passed by value (postblit and all), which is quite wasteful. As such, I'd want something like: void foo(Args...)(auto ref Args args) {foo(args);} void foo(Args...)(ref Args args) {...} Unfortunately, this doesn't work, since the compiler considers these to be equal matches. The workaround is: //---- enum isRef(alias arg) = __traits(isRef, arg); auto foo(Args...)(auto ref Args args) if (!allSatisfy!(isRef, args)) { ... } auto foo(Args...)(ref Args args) { ... } //---- But this is rather ugly and unpleasant. I think the compiler should notice that there is an overload that takes only references, and as such, is a "better match" than the auto-ref version.
Comment #1 by razvan.nitu1305 — 2022-08-22T15:31:08Z
Unfortunately, I don't think that this bug report is going to get fixed. Since both foo() functions are templated, they have to be instantiated before overload resolution is performed. The auto ref variadic function will eventually be instantiated as ref or not ref. That's were you get the conflict from. What is requested here is to modify the overload resolution rules based on auto refness. The current overloading rules have been proven to work well and Walter is always reluctant to modifying them. So, I don't think that this bug report is ever going to get "fixed". Either way, the proposed workaround is not ugly at all. Tentatively, closing as this as WONTFIX.