www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Rvalue forwarding

reply "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
next sibling parent "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
prev sibling parent "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