www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - move an argument tuple

reply Shachar Shemesh <shachar weka.io> writes:
Hi everybody,

I'm trying to have a templated function like so:

     void func(alias F)(Parameters!F args) {

At some point in func, I want to call F with args:
    F(args);

This does not work if one of args is a struct with copying disabled. 
That's fine. What I'd like to do is to move it into F:
    F( move(args) );

Except that only works if args.length==1. If args.length==2, it thinks 
I'm calling the move overload that moves from the first argument to the 
second, and then it complains that F cannot be called with void argument.

Things that also don't work:
   F( moveAll(args) );
That one accepts two ranges and expects to copy between them.

I guess I can put up a mixin that expands to:
   F( move(args[0]), move(args[1]) );

I'd really like a cleaner solution if one is possible.

Thanks,
Shachar
Dec 07 2017
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, December 07, 2017 10:19:25 Shachar Shemesh via Digitalmars-d 
wrote:
 Hi everybody,

 I'm trying to have a templated function like so:

      void func(alias F)(Parameters!F args) {

 At some point in func, I want to call F with args:
     F(args);

 This does not work if one of args is a struct with copying disabled.
 That's fine. What I'd like to do is to move it into F:
     F( move(args) );

 Except that only works if args.length==1. If args.length==2, it thinks
 I'm calling the move overload that moves from the first argument to the
 second, and then it complains that F cannot be called with void argument.

 Things that also don't work:
    F( moveAll(args) );
 That one accepts two ranges and expects to copy between them.

 I guess I can put up a mixin that expands to:
    F( move(args[0]), move(args[1]) );

 I'd really like a cleaner solution if one is possible.
My first inclination is to suggest that you make the function accept all its arguments by ref and then call move internally, though that only makes sense if you're _always_ going to do a move. I believe that this will work though: void foo(alias func)(ref Parameters!func args) And then you can do something like foreach(arg; args) { // do move call on arg } inside. All of that gets nastier though if you're trying to make it so that moves are only done in some cases, and ultimately, doing a mixin like you were thinking of might be nicer. The cleanest thing would probably be if you could just use ref and not bother moving anything, but whether that makes sense or not depends on what you're doing. - Jonathan M Davis
Dec 07 2017
parent Shachar Shemesh <shachar weka.io> writes:
On 07/12/17 10:46, Jonathan M Davis wrote:
 
 My first inclination is to suggest that you make the function accept all its
 arguments by ref and then call move internally, though that only makes sense
 if you're _always_ going to do a move. I believe that this will work though:
That won't work for me because of a detail I've left out - I'm doing an interim move into a temporary buffer. In fact, I actually forbid ref arguments (though I could have converted them to a pointer on input and back to a reference on call, but it's actually a reasonable restriction for me to just forbid this outright). Shachar
Dec 07 2017
prev sibling parent Atila Neves <atila.neves gmail.com> writes:
On Thursday, 7 December 2017 at 08:19:25 UTC, Shachar Shemesh 
wrote:
 Hi everybody,

 I'm trying to have a templated function like so:

     void func(alias F)(Parameters!F args) {

 At some point in func, I want to call F with args:
    F(args);

 This does not work if one of args is a struct with copying 
 disabled. That's fine. What I'd like to do is to move it into F:
    F( move(args) );

 Except that only works if args.length==1. If args.length==2, it 
 thinks I'm calling the move overload that moves from the first 
 argument to the second, and then it complains that F cannot be 
 called with void argument.

 Things that also don't work:
   F( moveAll(args) );
 That one accepts two ranges and expects to copy between them.

 I guess I can put up a mixin that expands to:
   F( move(args[0]), move(args[1]) );

 I'd really like a cleaner solution if one is possible.

 Thanks,
 Shachar
import std.traits: Parameters; import std.stdio: writeln; import std.functional: forward; struct Foo { int i; disable this(this); } auto add(Foo f, Foo g) { return f.i + g.i; } void main() { func!add(Foo(1), Foo(2)); } void func(alias F)(Parameters!F args) { writeln(F(forward!args)); }
Dec 07 2017