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
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
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
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