| Thread overview | |||||
|---|---|---|---|---|---|
|
February 23, 2012 Rvalue forwarding | ||||
|---|---|---|---|---|
| ||||
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;
}
| ||||
February 23, 2012 Re: Rvalue forwarding | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Martin Nowak | 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 | |||
February 24, 2012 Re: Rvalue forwarding | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Martin Nowak | 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
}
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply