Thread overview
move an argument tuple
Dec 07, 2017
Shachar Shemesh
Dec 07, 2017
Jonathan M Davis
Dec 07, 2017
Shachar Shemesh
Dec 07, 2017
Atila Neves
December 07, 2017
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
December 07, 2017
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

December 07, 2017
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
December 07, 2017
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));
}