www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - how to handle void arguments in generic programming ?

reply Timothee Cour <thelastmammoth gmail.com> writes:
The code snippet below doesn't work. Is there a way to make it work?

import std.stdio;
void main(){
  writelnIfNonVoid(writeln("ok"));
}
void writelnIfNonVoid(T...)(T a){
  static if(T.length)
    writeln(a);
}
Nov 10 2013
next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 11 November 2013 at 03:52:16 UTC, Timothee Cour wrote:
 The code snippet below doesn't work. Is there a way to make it 
 work?

 import std.stdio;
 void main(){
   writelnIfNonVoid(writeln("ok"));
 }
 void writelnIfNonVoid(T...)(T a){
   static if(T.length)
     writeln(a);
 }
Considering "cannot have parameters of type void" error, I doubt it. Using lambda can do as workaround though (returning void is legal): import std.stdio; import std.traits; void main() { writelnIfNonVoid(() { writeln("ok"); }); } void writelnIfNonVoid(T)(T f) if (isSomeFunction!T) { static if (!is(ReturnType!T == void)) writeln(a); }
Nov 11 2013
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11/11/2013 04:52 AM, Timothee Cour wrote:
 The code snippet below doesn't work. Is there a way to make it work?

 import std.stdio;
 void main(){
    writelnIfNonVoid(writeln("ok"));
 }
 void writelnIfNonVoid(T...)(T a){
    static if(T.length)
      writeln(a);
 }
import std.stdio; void main(){ writelnIfNonVoid(writeln("ok")); } void writelnIfNonVoid(T...)(lazy T a){ static if(T.length){ static if(is(T[0]==void)) a[0]; else write(a[0]); static if(T.length==1) writeln(); else writelnIfNonVoid(a[1..$]); } } Or, if you care about evaluation order and locking stdout: import std.stdio; void main(){ writelnIfNonVoid(writeln("ok")); } void writelnIfNonVoid(T...)(lazy T a){ import std.range, std.algorithm, std.conv; mixin({ string[] indices=iota(a.length).map!(i=>"a["~to!string(i)~"]").array~"cast(void)0"; string r; foreach(i,t;T){ if(is(t==void)) indices[i+1]="("~indices[i]~","~indices[i+1]~")"; else r~=indices[i]~","; } if(r.length) r="writeln("~r~");"; return r~indices[$-1]~";"; }()); }
Nov 11 2013
next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 11 November 2013 at 13:06:14 UTC, Timon Gehr wrote:
 void writelnIfNonVoid(T...)(lazy T a){
Whoa, one can apply attributes to variadic argument list? Yummy!
Nov 11 2013
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 11/11/2013 02:06 PM, Timon Gehr wrote:
 Or, if you care about evaluation order and locking stdout:
This was a little too quick. It does not work too well since if the last parameter is of type void, the newline is emitted before the trailing arguments of type void are evaluated, which may not be exactly what you wanted. The following should work, however DMD does not properly support the (exp,Seq!()) construct, so it won't compile in this case: alias Seq(T...)=T; void writelnIfNonVoid(T...)(lazy T a){ import std.range, std.algorithm, std.conv; mixin({ string[] indices=iota(a.length).map!(i=>"a["~to!string(i)~"]").array~"Seq!()"; string r; foreach(i,t;T){ if(is(t==void)) indices[i+1]="("~indices[i]~","~indices[i+1]~")"; else r~=indices[i]~","; } if(r.length) return "writeln("~r~indices[$-1]~");"; return indices[$-1]!="Seq!()"?indices[$-1]~";":""; }()); } This could be worked around as follows, but then you might get more postblit invocations than in the previous version: import std.stdio; void main(){ writelnIfNonVoid("123",writeln("ok")); } void writelnIfNonVoid(T...)(lazy T a){ import std.conv; static if(T.length) mixin({ string r,args; foreach(i,t;T){ if(!is(t==void)){ r~="auto r_"~to!string(i)~"="; args~="r_"~to!string(i)~","; } r~="a["~to!string(i)~"];"; } return r~"writeln("~args~");"; }()); } (Not sure what you intended the exact rules for emmiting a line feed character to be.)
Nov 11 2013