digitalmars.D - Rvalue forwarding

• Martin Nowak (87/87) Feb 22 2012 Is it possible to forward rvalues through variadic templates?
• H. S. Teoh (12/40) Feb 23 2012 [...]
• Martin Nowak (49/52) Feb 23 2012 A working solution was to let move return a proxy which defers the move
"Martin Nowak" <dawg dawgfoto.de> writes:
```Is it possible to forward rvalues through variadic templates?
Having to "move" the value for every layer is suboptimal.
What am I doing wrong?

----------

import std.algorithm : move;

void foo(Unique!Handle uniq)
{
auto val = uniq.extract;
assert(val._fd == 1);
val.close();
}

void foo(Unique!Handle uniq, string)
{
auto val = uniq.extract;
assert(val._fd == 1);
val.close();
}

version (none)
{
void bar(Args...)(Args args)
{
foo(move(args)); // cannot forward variadic arguments ???
}
}
else
{
void bar(A0)(A0 a0)
{
foo(move(a0));
}

void bar(A0, A1)(A0 a0, A1 a1)
{
foo(move(a0), move(a1));
}
}

void main()
{
Unique!Handle uniq;

uniq = Unique!Handle(Handle(1));
assert(uniq._obj._fd == 1);
bar(move(uniq));
assert(uniq._obj._fd == 0);
uniq = Unique!Handle(Handle(1));
assert(uniq._obj._fd == 1);
bar(move(uniq), "other arg");
assert(uniq._obj._fd == 0);
}

//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

struct Handle
{
this(int fd)
{
_fd = fd;
assert(_fd);
}

void close()
{
_fd = 0;
}

~this()
{
assert(!_fd);
}

int _fd;
}

struct Unique(T)
{
this()(auto ref T val) if(!__traits(isRef, val))
{
move(val, _obj);
}

this()(auto ref Unique!T val) if(!__traits(isRef, val))
{
move(val._obj, _obj);
}

disable this(this);

void opAssign(Unique val)
{
move(val._obj, _obj);
}

property T extract()
{
return move(_obj);
}

private:
T _obj;
}
```
Feb 22 2012
"H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
```On Thu, Feb 23, 2012 at 08:15:52AM +0100, Martin Nowak wrote:
Is it possible to forward rvalues through variadic templates?
Having to "move" the value for every layer is suboptimal.
What am I doing wrong?

----------

import std.algorithm : move;

void foo(Unique!Handle uniq)
{
auto val = uniq.extract;
assert(val._fd == 1);
val.close();
}

void foo(Unique!Handle uniq, string)
{
auto val = uniq.extract;
assert(val._fd == 1);
val.close();
}

version (none)
{
void bar(Args...)(Args args)
{
foo(move(args)); // cannot forward variadic arguments ???
}

[...]

I'm not sure, but doesn't this only work if foo() is also variadic?
Otherwise I'm not sure how the compiler is supposed to determine, at
compile-time, which overload of foo to call from here. And what if args
contains 3 arguments, or arguments that don't match any overload of foo?

I suppose this *could* be handled by generating runtime code to decide
which foo to call, but from what I understand, D doesn't support this
currently.

T

--
Only boring people get bored. -- JM
```
Feb 23 2012
"Martin Nowak" <dawg dawgfoto.de> writes:
```On Thu, 23 Feb 2012 08:15:52 +0100, Martin Nowak <dawg dawgfoto.de> wrote:

Is it possible to forward rvalues through variadic templates?
Having to "move" the value for every layer is suboptimal.
What am I doing wrong?

A working solution was to let move return a proxy which defers the move
until it gets implicitly converted into an rvalue.

auto move(T)(ref T src)
{
/* Non-instantiable non-copyable proxy to forward moves.
*/
static struct Proxy(T)
{
static import std.algorithm;

~this()
{
if (_ptr !is null)
{
typeid(T).destroy(_ptr);
_ptr = null;
}
}

/* Triggers move on implicit conversion.
*/
property T get()
{
auto p = _ptr; _ptr = null;
return std.algorithm.move(*p);
}

alias get this;

private:
disable this();
disable this(this);

this(T *p) { _ptr = p; }
T* _ptr;
}

return Proxy!T(&src);
}

The proxy can be forwarded, but has the downside that one can escape
references.

auto foo()
{
int val;
return move(val); // ouch
}

void bar()
{
{
int a;
auto m = move(a);
}
int b = m; // ouch
}
```
Feb 23 2012