Thread overview
Unpack Variadic Args?
Feb 13, 2020
Jeff
Feb 13, 2020
Paul Backus
Feb 13, 2020
Jeff
Feb 13, 2020
Adam D. Ruppe
Feb 13, 2020
H. S. Teoh
February 13, 2020
Hello,

Was wondering if there was a simple, efficient way to unpack a variadic template argument. It needs to be efficient at runtime, and hopefully not use too much excessive CTFE.

C++ has the "..." operator, is there something equivalent in D?

    template<class ...Args>
    void g(Args... args) {
        f(foo(args)...); // f(foo(args[0]), foo(args[1])); // etc
    }

What would be a good way to write that in D, with it being as efficient (no copies or building structs etc) and not use too much CTFE. Needing to use `.map` or similar at CTFE would be an example of too much CTFE.

    void g(Args...)(auto ref Args args) {
         // ?
    }
February 13, 2020
On Thursday, 13 February 2020 at 07:06:49 UTC, Jeff wrote:
> Hello,
>
> Was wondering if there was a simple, efficient way to unpack a variadic template argument. It needs to be efficient at runtime, and hopefully not use too much excessive CTFE.
>
> C++ has the "..." operator, is there something equivalent in D?
>
>     template<class ...Args>
>     void g(Args... args) {
>         f(foo(args)...); // f(foo(args[0]), foo(args[1])); // etc
>     }
>
> What would be a good way to write that in D, with it being as efficient (no copies or building structs etc) and not use too much CTFE. Needing to use `.map` or similar at CTFE would be an example of too much CTFE.
>
>     void g(Args...)(auto ref Args args) {
>          // ?
>     }

Variadic template arguments unpack automatically in D, so you don't need to do anything special here:

    void g(Args...)(auto ref Args args) {
        import core.lifetime: forward; // like std::forward
        f(forward!args);
    }

You can read more about variadic template arguments in this article:

https://dlang.org/articles/ctarguments.html
February 13, 2020
On Thursday, 13 February 2020 at 08:06:52 UTC, Paul Backus wrote:
> On Thursday, 13 February 2020 at 07:06:49 UTC, Jeff wrote:
>> Hello,
>>
>> Was wondering if there was a simple, efficient way to unpack a variadic template argument. It needs to be efficient at runtime, and hopefully not use too much excessive CTFE.
>>
>> C++ has the "..." operator, is there something equivalent in D?
>>
>>     template<class ...Args>
>>     void g(Args... args) {
>>         f(foo(args)...); // f(foo(args[0]), foo(args[1])); // etc
>>     }
>>
>> What would be a good way to write that in D, with it being as efficient (no copies or building structs etc) and not use too much CTFE. Needing to use `.map` or similar at CTFE would be an example of too much CTFE.
>>
>>     void g(Args...)(auto ref Args args) {
>>          // ?
>>     }
>
> Variadic template arguments unpack automatically in D, so you don't need to do anything special here:
>
>     void g(Args...)(auto ref Args args) {
>         import core.lifetime: forward; // like std::forward
>         f(forward!args);
>     }
>
> You can read more about variadic template arguments in this article:
>
> https://dlang.org/articles/ctarguments.html

That would result in the call:

    f( args[0], args[1], ... );

But the C++ version does the following:

    f( foo(args[0]), foo(args[1]), ... );

They are different.
February 13, 2020
On 2/13/20 11:29 AM, Jeff wrote:
> On Thursday, 13 February 2020 at 08:06:52 UTC, Paul Backus wrote:
>> Variadic template arguments unpack automatically in D, so you don't need to do anything special here:
>>
>>     void g(Args...)(auto ref Args args) {
>>         import core.lifetime: forward; // like std::forward
>>         f(forward!args);
>>     }
>>
>> You can read more about variadic template arguments in this article:
>>
>> https://dlang.org/articles/ctarguments.html
> 
> That would result in the call:
> 
>      f( args[0], args[1], ... );
> 
> But the C++ version does the following:
> 
>      f( foo(args[0]), foo(args[1]), ... );
> 
> They are different.

the f(foo(args)...) syntax doesn't have a D equivalent.

I don't think it's possible to do without some form of mixin. While compile-time lists are available, they must be strictly made of things that are either CTFE expressions or symbols.

A possible mixin solution:

string doMixin(T...)(string formatspec)
{
   string result;
   import std.format: format;
   static foreach(i; 0 .. T.length)
      result ~= format(formatspec, __traits(identifier, T[i])) ~ ",";
   return result[0 .. $-1]; // trim last comma
}

void g(T...)(T args) {
   mixin("f(" ~ doMixin!args("foo(%s)") ~ ");");
}

-Steve
February 13, 2020
On Thursday, 13 February 2020 at 17:13:31 UTC, Steven Schveighoffer wrote:
> the f(foo(args)...) syntax doesn't have a D equivalent.

It would be staticMap <http://dpldocs.info/experimental-docs/std.meta.staticMap.html>

f(staticMap!(foo, args))

staticMap is a recursive template <http://dpldocs.info/experimental-docs/source/std.meta.d.html#L785> so no mixin stuff

but it can get CT memory heavy in some cases due to all the instantiations. i say the compiler should just do this better. but really it works for the most part.
February 13, 2020
On 2/13/20 12:18 PM, Adam D. Ruppe wrote:
> On Thursday, 13 February 2020 at 17:13:31 UTC, Steven Schveighoffer wrote:
>> the f(foo(args)...) syntax doesn't have a D equivalent.
> 
> It would be staticMap <http://dpldocs.info/experimental-docs/std.meta.staticMap.html>
> 
> f(staticMap!(foo, args))

No, this does foo!(args[0]), foo!(args[1])...).

He wants a runtime call to each arg wrapped with foo.

One could do:

auto wrapFoo(alias arg)() { return foo(arg); }

and then f(staticMap!(wrapFoo, args));

But this means you have an additional function call (which could of course be inlined). It is a viable solution though (tested, and it does work).

-Steve
February 13, 2020
On 2/13/20 12:24 PM, Steven Schveighoffer wrote:
> But this means you have an additional function call (which could of course be inlined).

And I might add, an additional requirement to declare some other template (one of the huge drawbacks of std.meta, IMO).

Some syntax like expr(someTuple)... would be really cool to have in D.

Or something like arg => expr syntax for templates might be useful:

f(staticMap!(!a => foo(a), args)); // look ma, anonymous template!

-Steve
February 13, 2020
On Thu, Feb 13, 2020 at 12:32:01PM -0500, Steven Schveighoffer via Digitalmars-d-learn wrote: [...]
> Some syntax like expr(someTuple)... would be really cool to have in D.
> 
> Or something like arg => expr syntax for templates might be useful:
> 
> f(staticMap!(!a => foo(a), args)); // look ma, anonymous template!
[...]

Yes, yes, and yes!  Anonymous templates would make std.traits and std.meta *much* easier to use.


T

-- 
"I'm running Windows '98." "Yes." "My computer isn't working now." "Yes, you already said that." -- User-Friendly