www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Can't use variadic arguments to functions that use templates

reply "JS" <js.mdnq gmail.com> writes:
variadic parameters are suppose to make life easier but it seems 
those don't work with templates.

template A(int L) { ... }

void foo(T)(string s, T t...)
{
    A!(t.length);

}

gives error t can't be read at compile time.

I understand in general why this works BUT I will only ever use 
foo where the number of arguments are known at compile time.

Therefor to get the code to work I have to revert back to the old 
way of overloading foo many times to emulate variadic parameters.

Essentially all I want to do is to use foo like

foo("a", "b", "c", 'd', s, ...) but the number of arguments is 
fixed at compile time(almost all arguments are, aren't they?).


Here is a challenge:

Write a function that accepts any number of string or character 
variables or literals and returns the concatenates them 
efficiently as possible(as efficient as fixed arguments).

e.g.,

foo1(string s) { return s; }
foo2(string s1, string s2) { return s1~s2; }
etc...

if we had compile time variadic parameters, we could do something 
like

foo(T t$...) { return mixin(concat!t); } where concat produces 
the string t[0]~t[1]~t[2]... which produces the same code as the 
overloaded case, but must simpler.

I don't think this is possible because there is no static version 
of variadic arguments, i.e., one who's length is always known at 
compile time.
Jul 20 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
JS:

 variadic parameters are suppose to make life easier but it 
 seems those don't work with templates.

 template A(int L) { ... }

 void foo(T)(string s, T t...)
 {
    A!(t.length);

 }
Try this: template A(size_t L) { enum A = L; } void foo(T...)(string s, T t) { auto n = A!(t.length); } void main() { foo("x", 1, 2); } Bye, bearophile
Jul 20 2013
next sibling parent "JS" <js.mdnq gmail.com> writes:
On Saturday, 20 July 2013 at 17:39:59 UTC, bearophile wrote:
 JS:

 variadic parameters are suppose to make life easier but it 
 seems those don't work with templates.

 template A(int L) { ... }

 void foo(T)(string s, T t...)
 {
   A!(t.length);

 }
Try this: template A(size_t L) { enum A = L; } void foo(T...)(string s, T t) { auto n = A!(t.length); } void main() { foo("x", 1, 2); } Bye, bearophile
;/ I could have swore I tried that ;/ Thanks though! ;)
Jul 20 2013
prev sibling parent reply "JS" <js.mdnq gmail.com> writes:
On Saturday, 20 July 2013 at 17:39:59 UTC, bearophile wrote:
 JS:

 variadic parameters are suppose to make life easier but it 
 seems those don't work with templates.

 template A(int L) { ... }

 void foo(T)(string s, T t...)
 {
   A!(t.length);

 }
Try this: template A(size_t L) { enum A = L; } void foo(T...)(string s, T t) { auto n = A!(t.length); } void main() { foo("x", 1, 2); } Bye, bearophile
is there any way to pass t directly to A? template A(T...) doesn't seem work nor does using an alias. (or at least, when I try to foreach over it, it doesn't work).
Jul 20 2013
parent reply "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Saturday, 20 July 2013 at 18:27:23 UTC, JS wrote:
 is there any way to pass t directly to A?

 template A(T...) doesn't seem work nor does using an alias. (or 
 at least, when I try to foreach over it, it doesn't work).
template A(size_t L) { enum A = L; } template B(T...) { void B(T b) { import std.stdio; foreach(Type; T) { pragma(msg, Type.stringof); } foreach(v; b) { writeln(v); } }} void foo(T...)(string s, T t) { auto n = A!(t.length); B(t);// t is runtime information // T is compile time information } void main() { foo("x", 1, 2); }
Jul 20 2013
parent reply "JS" <js.mdnq gmail.com> writes:
On Saturday, 20 July 2013 at 18:57:18 UTC, Jesse Phillips wrote:
 On Saturday, 20 July 2013 at 18:27:23 UTC, JS wrote:
 is there any way to pass t directly to A?

 template A(T...) doesn't seem work nor does using an alias. 
 (or at least, when I try to foreach over it, it doesn't work).
template A(size_t L) { enum A = L; } template B(T...) { void B(T b) { import std.stdio; foreach(Type; T) { pragma(msg, Type.stringof); } foreach(v; b) { writeln(v); } }} void foo(T...)(string s, T t) { auto n = A!(t.length); B(t);// t is runtime information // T is compile time information } void main() { foo("x", 1, 2); }
I know I tried that but: import std.cstream, std.stdio; template B(T...) { string B(T b) { string s; foreach(Type; T) pragma(msg, Type.stringof); foreach(v; b) s ~= v.stringof; return s; } } void foo(T...)(T t) { pragma(msg, B(t)); } void main() { foo("x", "a", "b"); din.getc(); } does work. I need to have B generate compile time code so it is efficient. Your method calls an actual function at runtime so it is nearly as fast as it can be.
Jul 21 2013
parent reply "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Sunday, 21 July 2013 at 07:22:08 UTC, JS wrote:
 void foo(T...)(T t)
 {
     pragma(msg, B(t));
 }

 void main() {
     foo("x", "a", "b");
 	din.getc();
 }


 does work. I need to have B generate compile time code so it is 
 efficient. Your method calls an actual function at runtime so 
 it is nearly as fast as it can be.
My method doesn't make any calls, your foo is a called at runtime. There is no way to observe a function at compile time; ctfeWriteln does not exist. Also don't stringof variable v (I assume you want the value and not the symbol concatenated. template B(T...) { string B(T b) { string s; foreach(Type; T) pragma(msg, Type.stringof); foreach(v; b) s ~= v; return s; } } string foo(T...)(T t) { return B(t); } void main() { enum forced = foo("x", "a", "b"); pragma(msg, forced); din.getc(); }
Jul 22 2013
parent reply "JS" <js.mdnq gmail.com> writes:
On Monday, 22 July 2013 at 16:48:56 UTC, Jesse Phillips wrote:
 On Sunday, 21 July 2013 at 07:22:08 UTC, JS wrote:
 void foo(T...)(T t)
 {
    pragma(msg, B(t));
 }

 void main() {
    foo("x", "a", "b");
 	din.getc();
 }


 does work. I need to have B generate compile time code so it 
 is efficient. Your method calls an actual function at runtime 
 so it is nearly as fast as it can be.
My method doesn't make any calls, your foo is a called at runtime. There is no way to observe a function at compile time; ctfeWriteln does not exist. Also don't stringof variable v (I assume you want the value and not the symbol concatenated. template B(T...) { string B(T b) { string s; foreach(Type; T) pragma(msg, Type.stringof); foreach(v; b) s ~= v; return s; } } string foo(T...)(T t) { return B(t); } void main() { enum forced = foo("x", "a", "b"); pragma(msg, forced); din.getc(); }
I don't think you understand(or I've already got confused)... I'm trying to use B has a mixin(I don't think I made this clear). I can't use it as a normal function. e.g., I can't seem to do mixin(B(t)). If I could, this would definitely solve my problem. Here is a real world example: template VariadicLoop(T...) { pragma(msg, T); string VariadicLoop(T t) { string s; foreach(k; T) s ~= k.stringof; foreach(v; t) s ~= v; return s; } //enum tVariadicLoop = eval(); //pragma(msg, tVariadicLoop); } string join(T...)(string delim, T t) { return mixin(VariadicLoop(t)); } VariadicLoop should join the strings passed to join(producing whatever code is necessary to do this efficiently. e.g., join(",", "a", s) should result in the code for join: { return "a"~","~s; // s maybe t[1] or something } This is the most efficient way to join rather than using a foreach over an array of strings or something or another. (VariadicLoop could handle string[]'s and insert the appropriate code to join them) The goal I'm trying to solve is efficiently deal with variadic arguments that are compile time calculable along with mixing in the runtime aspect. Basically: get the compiler to do all the work it can before having it done at runtime. if we are passing string literals to join then they can be joined at compile time. If we are passing a combination of string literals, string variables, and string arrays then we deal with each part efficiently as possible.
Jul 23 2013
parent reply "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Tuesday, 23 July 2013 at 14:03:01 UTC, JS wrote:
 I don't think you understand(or I've already got confused)...

 I'm trying to use B has a mixin(I don't think I made this 
 clear). I can't use it as a normal function. e.g., I can't seem 
 to do mixin(B(t)). If I could, this would definitely solve my 
 problem.
I'll stick with the reduced example, maybe you can apply it to the real world: template B(T...) { string B(T b) { string s; foreach(i, Type; T) s ~= Type.stringof ~ " " ~ b[i] ~ ";\n"; return s; } } void main() { enum forced = B("x", "a", "b"); pragma(msg, forced); mixin(forced); }
Jul 23 2013
parent reply "JS" <js.mdnq gmail.com> writes:
On Tuesday, 23 July 2013 at 16:15:03 UTC, Jesse Phillips wrote:
 On Tuesday, 23 July 2013 at 14:03:01 UTC, JS wrote:
 I don't think you understand(or I've already got confused)...

 I'm trying to use B has a mixin(I don't think I made this 
 clear). I can't use it as a normal function. e.g., I can't 
 seem to do mixin(B(t)). If I could, this would definitely 
 solve my problem.
I'll stick with the reduced example, maybe you can apply it to the real world: template B(T...) { string B(T b) { string s; foreach(i, Type; T) s ~= Type.stringof ~ " " ~ b[i] ~ ";\n"; return s; } } void main() { enum forced = B("x", "a", "b"); pragma(msg, forced); mixin(forced); }
What good does that do? What if I want to use a run-time variable in the mix?
Jul 23 2013
next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 07/23/2013 09:22 AM, JS wrote:

 On Tuesday, 23 July 2013 at 16:15:03 UTC, Jesse Phillips wrote:
 On Tuesday, 23 July 2013 at 14:03:01 UTC, JS wrote:
 I don't think you understand(or I've already got confused)...

 I'm trying to use B has a mixin(I don't think I made this clear). I
 can't use it as a normal function. e.g., I can't seem to do
 mixin(B(t)). If I could, this would definitely solve my problem.
I'll stick with the reduced example, maybe you can apply it to the real world: template B(T...) { string B(T b) { string s; foreach(i, Type; T) s ~= Type.stringof ~ " " ~ b[i] ~ ";\n"; return s; } } void main() { enum forced = B("x", "a", "b"); pragma(msg, forced); mixin(forced); }
What good does that do?
Makes a string, mixes it into the source code and then compiles it.
 What if I want to use a run-time variable in the mix?
Just pass the runtime values to the template: import std.stdio; void main(string[] args) { if (args.length > 2) { writeln(B(args[1], args[2])); } } $ ./deneme abc xyz string abc; string xyz; That is pretty amazing that the same function can be called at compile time and runtime. Ali
Jul 23 2013
prev sibling parent reply "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Tuesday, 23 July 2013 at 16:22:38 UTC, JS wrote:
 On Tuesday, 23 July 2013 at 16:15:03 UTC, Jesse Phillips wrote:
 On Tuesday, 23 July 2013 at 14:03:01 UTC, JS wrote:
 I don't think you understand(or I've already got confused)...

 I'm trying to use B has a mixin(I don't think I made this 
 clear). I can't use it as a normal function. e.g., I can't 
 seem to do mixin(B(t)). If I could, this would definitely 
 solve my problem.
...[Code]...
What good does that do? What if I want to use a run-time variable in the mix?
Ah, I understand now you're interested in: string concat(alias Data...)() { ... } This does not exist, but maybe it should... I don't know of a workaround to get this behavior.
Jul 23 2013
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Jul 23, 2013 at 08:54:12PM +0200, Jesse Phillips wrote:
 On Tuesday, 23 July 2013 at 16:22:38 UTC, JS wrote:
On Tuesday, 23 July 2013 at 16:15:03 UTC, Jesse Phillips wrote:
On Tuesday, 23 July 2013 at 14:03:01 UTC, JS wrote:
I don't think you understand(or I've already got confused)...

I'm trying to use B has a mixin(I don't think I made this
clear). I can't use it as a normal function. e.g., I can't
seem to do mixin(B(t)). If I could, this would definitely
solve my problem.
...[Code]...
What good does that do? What if I want to use a run-time variable in the mix?
Ah, I understand now you're interested in: string concat(alias Data...)() { ... } This does not exist, but maybe it should... I don't know of a workaround to get this behavior.
Is this by any chance related to that other thread about compile-time optimized join()? 'cos if it is, I've already solved the problem via templates: import std.stdio; template tuple(args...) { alias tuple = args; } /** * Given a tuple of strings, returns a tuple in which all adjacent compile-time * readable strings are concatenated. */ template tupleReduce(args...) { static if (args.length > 1) { static if (is(typeof(args[0])==string) && __traits(compiles, { enum x = args[0]; })) { static if (is(typeof(args[1])==string) && __traits(compiles, { enum x = args[1]; })) { alias tupleReduce = tupleReduce!(args[0] ~ args[1], args[2..$]); } else { alias tupleReduce = tuple!(args[0], args[1], tupleReduce!(args[2..$])); } } else { alias tupleReduce = tuple!(args[0], tupleReduce!(args[1..$])); } } else { alias tupleReduce = args; } } void main() { string x = "runtime1"; string y = "runtime2"; auto arr = [ tupleReduce!("a", "b", x, "c", "d", y, "e", "f", "g", x) ]; writeln(arr); } The output is: ["ab", "runtime1", "cd", "runtime2", "efg", "runtime1"] All compile-time readable strings in the list have been concatenated at compile-time. T -- I don't trust computers, I've spent too long programming to think that they can get anything right. -- James Miller
Jul 23 2013
parent "JS" <js.mdnq gmail.com> writes:
On Tuesday, 23 July 2013 at 19:14:26 UTC, H. S. Teoh wrote:
 On Tue, Jul 23, 2013 at 08:54:12PM +0200, Jesse Phillips wrote:
 On Tuesday, 23 July 2013 at 16:22:38 UTC, JS wrote:
On Tuesday, 23 July 2013 at 16:15:03 UTC, Jesse Phillips 
wrote:
On Tuesday, 23 July 2013 at 14:03:01 UTC, JS wrote:
I don't think you understand(or I've already got 
confused)...

I'm trying to use B has a mixin(I don't think I made this
clear). I can't use it as a normal function. e.g., I can't
seem to do mixin(B(t)). If I could, this would definitely
solve my problem.
...[Code]...
What good does that do? What if I want to use a run-time variable in the mix?
Ah, I understand now you're interested in: string concat(alias Data...)() { ... } This does not exist, but maybe it should... I don't know of a workaround to get this behavior.
Is this by any chance related to that other thread about compile-time optimized join()? 'cos if it is, I've already solved the problem via templates: import std.stdio; template tuple(args...) { alias tuple = args; } /** * Given a tuple of strings, returns a tuple in which all adjacent compile-time * readable strings are concatenated. */ template tupleReduce(args...) { static if (args.length > 1) { static if (is(typeof(args[0])==string) && __traits(compiles, { enum x = args[0]; })) { static if (is(typeof(args[1])==string) && __traits(compiles, { enum x = args[1]; })) { alias tupleReduce = tupleReduce!(args[0] ~ args[1], args[2..$]); } else { alias tupleReduce = tuple!(args[0], args[1], tupleReduce!(args[2..$])); } } else { alias tupleReduce = tuple!(args[0], tupleReduce!(args[1..$])); } } else { alias tupleReduce = args; } } void main() { string x = "runtime1"; string y = "runtime2"; auto arr = [ tupleReduce!("a", "b", x, "c", "d", y, "e", "f", "g", x) ]; writeln(arr); } The output is: ["ab", "runtime1", "cd", "runtime2", "efg", "runtime1"] All compile-time readable strings in the list have been concatenated at compile-time. T
Thanks, I'll check it out when I get a chance and report back. It looks like it solves the problem.
Jul 23 2013