www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Unpack Variadic Args?

reply Jeff <jeff.monkey.wrench.thirtytwo gmail.com> writes:
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) {
          // ?
     }
Feb 12 2020
parent reply Paul Backus <snarwin gmail.com> writes:
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
Feb 13 2020
parent reply Jeff <jeff.monkey.wrench.thirtytwo gmail.com> writes:
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.
Feb 13 2020
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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
Feb 13 2020
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
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.
Feb 13 2020
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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
Feb 13 2020
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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
Feb 13 2020
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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
Feb 13 2020