Merge pull request #5348 from radcapricorn/forward

forward: single argument, copy const
This commit is contained in:
Sebastian Wilzbach 2018-01-17 09:51:45 +01:00 committed by GitHub
commit c8d8fe0c83
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1477,11 +1477,20 @@ template forward(args...)
import std.algorithm.mutation : move; import std.algorithm.mutation : move;
alias arg = args[0]; alias arg = args[0];
static if (__traits(isRef, arg)) // by ref || lazy || const/immutable
static if (__traits(isRef, arg) ||
__traits(isOut, arg) ||
__traits(isLazy, arg) ||
!is(typeof(move(arg))))
alias fwd = arg; alias fwd = arg;
// (r)value
else else
@property fwd()(){ return move(arg); } @property auto fwd(){ return move(arg); }
alias forward = AliasSeq!(fwd, forward!(args[1..$]));
static if (args.length == 1)
alias forward = fwd;
else
alias forward = AliasSeq!(fwd, forward!(args[1..$]));
} }
else else
alias forward = AliasSeq!(); alias forward = AliasSeq!();
@ -1562,3 +1571,116 @@ template forward(args...)
int value = 3; int value = 3;
auto x2 = bar(value); // case of OK auto x2 = bar(value); // case of OK
} }
///
@safe unittest
{
struct X {
int i;
this(this)
{
++i;
}
}
struct Y
{
private X x_;
this()(auto ref X x)
{
x_ = forward!x;
}
}
struct Z
{
private const X x_;
this()(auto ref X x)
{
x_ = forward!x;
}
this()(auto const ref X x)
{
x_ = forward!x;
}
}
X x;
const X cx;
auto constX = (){ const X x; return x; };
static assert(__traits(compiles, { Y y = x; }));
static assert(__traits(compiles, { Y y = X(); }));
static assert(!__traits(compiles, { Y y = cx; }));
static assert(!__traits(compiles, { Y y = constX(); }));
static assert(__traits(compiles, { Z z = x; }));
static assert(__traits(compiles, { Z z = X(); }));
static assert(__traits(compiles, { Z z = cx; }));
static assert(__traits(compiles, { Z z = constX(); }));
Y y1 = x;
// ref lvalue, copy
assert(y1.x_.i == 1);
Y y2 = X();
// rvalue, move
assert(y2.x_.i == 0);
Z z1 = x;
// ref lvalue, copy
assert(z1.x_.i == 1);
Z z2 = X();
// rvalue, move
assert(z2.x_.i == 0);
Z z3 = cx;
// ref const lvalue, copy
assert(z3.x_.i == 1);
Z z4 = constX();
// const rvalue, copy
assert(z4.x_.i == 1);
}
// lazy -> lazy
@safe unittest
{
int foo1(lazy int i) { return i; }
int foo2(A)(auto ref A i) { return foo1(forward!i); }
int foo3(lazy int i) { return foo2(i); }
int numCalls = 0;
assert(foo3({ ++numCalls; return 42; }()) == 42);
assert(numCalls == 1);
}
// lazy -> non-lazy
@safe unittest
{
int foo1(int a, int b) { return a + b; }
int foo2(A...)(auto ref A args) { return foo1(forward!args); }
int foo3(int a, lazy int b) { return foo2(a, b); }
int numCalls;
assert(foo3(11, { ++numCalls; return 31; }()) == 42);
assert(numCalls == 1);
}
// non-lazy -> lazy
@safe unittest
{
int foo1(int a, lazy int b) { return a + b; }
int foo2(A...)(auto ref A args) { return foo1(forward!args); }
int foo3(int a, int b) { return foo2(a, b); }
assert(foo3(11, 31) == 42);
}
// out
@safe unittest
{
void foo1(int a, out int b) { b = a; }
void foo2(A...)(auto ref A args) { foo1(forward!args); }
void foo3(int a, out int b) { foo2(a, b); }
int b;
foo3(42, b);
assert(b == 42);
}