mirror of
https://github.com/dlang/phobos.git
synced 2025-04-28 22:21:09 +03:00
Merge pull request #5348 from radcapricorn/forward
forward: single argument, copy const
This commit is contained in:
commit
c8d8fe0c83
1 changed files with 125 additions and 3 deletions
128
std/functional.d
128
std/functional.d
|
@ -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);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue