[Issue 12672] New: make "ref" a better match than "auto_ref" (especially for variadic arguments)
via Digitalmars-d-bugs
digitalmars-d-bugs at puremagic.com
Mon Apr 28 03:03:07 PDT 2014
https://issues.dlang.org/show_bug.cgi?id=12672
Issue ID: 12672
Summary: make "ref" a better match than "auto_ref" (especially
for variadic arguments)
Product: D
Version: D2
Hardware: All
OS: All
Status: NEW
Severity: enhancement
Priority: P1
Component: DMD
Assignee: nobody at puremagic.com
Reporter: monarchdodra at gmail.com
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.
--
More information about the Digitalmars-d-bugs
mailing list