digitalmars.D - Question about Template
- Michael (25/25) Jun 23 2012 Hello!
- simendsjo (23/48) Jun 23 2012 import std.datetime;
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (4/6) Jun 23 2012 F alone would mean a 'type', for example to be used in the template as
- Philippe Sigaud (59/69) Jun 23 2012 should I fix this problem?
- Michael (3/88) Jun 27 2012 Thank you all of you for your help!
Hello! I have a little question about templates. I am trying to write a template "timer" that takes a function and times how long the function takes to execute. Something like auto time = timer!sort(array); is equivalent to auto start = Clock.currStdTime(); sort(array); auto time = Clock.currStdTime() - time; except of course that the variable "start" is not created in the former case. The closest I came to the correct template is template(alias F) timer { auto timer { auto start = Clock.currStdTime(); F(); return Clock.currStdTime() - time; } } The problem with the template is I cannot pass any argument into "F". How should I fix this problem? Also, I am not entirely sure why I need to write "alias F" instead of just "F", any explanation would be appreciated. Thank you guys, Michael
Jun 23 2012
On Sat, 23 Jun 2012 17:30:01 +0200, Michael <pongad gmail.com> wrote:Hello! I have a little question about templates. I am trying to write a template "timer" that takes a function and times how long the function takes to execute. Something like auto time = timer!sort(array); is equivalent to auto start = Clock.currStdTime(); sort(array); auto time = Clock.currStdTime() - time; except of course that the variable "start" is not created in the former case. The closest I came to the correct template is template(alias F) timer { auto timer { auto start = Clock.currStdTime(); F(); return Clock.currStdTime() - time; } } The problem with the template is I cannot pass any argument into "F". How should I fix this problem? Also, I am not entirely sure why I need to write "alias F" instead of just "F", any explanation would be appreciated. Thank you guys, Michaelimport std.datetime; import std.traits; import std.stdio; struct TimerResult(T) { TickDuration duration; T result; } auto timer(alias fn, Args...)(Args args) { auto sw = StopWatch(AutoStart.yes); auto res = fn(args); return TimerResult!(typeof(res))(sw.peek, res); } T f(T)(T[] arr) { import core.thread; Thread.sleep(dur!"seconds"(1)); return arr[0]; } void main() { auto res = timer!f([1,2,3,4]); writeln("first elem: ", res.result); writeln("time used: ", res.duration.msecs); }
Jun 23 2012
On 06/23/2012 08:30 AM, Michael wrote:Also, I am not entirely sure why I need to write "alias F" instead of just "F", any explanation would be appreciated.F alone would mean a 'type', for example to be used in the template as F var; Ali
Jun 23 2012
The closest I came to the correct template is template(alias F) timer { auto timer { auto start = Clock.currStdTime(); F(); return Clock.currStdTime() - time; } }The problem with the template is I cannot pass any argument into "F". Howshould I fix this problem? As Simendsjo said, you can use a function template to get what you want and a nicer syntax as the same time. Slightly different code can be obtained by starting from the above code: template timer(alias F) // capture F's name { auto timer(Args...)(Args args) // there are your parameters { import std.datetime; // inner imports auto start = Clock.currStdTime(); F(args); return Clock.currStdTime() - start; } } So it's a template that gets expanded into another template with the same name, a function. Note that the construct: template (T...) { T foo(T t) // some function that depends on the template parameters { } } can get syntax sugar like this: T foo(T...)(T t) { } you can 'fuse' the external template and the inner code to get a function template. The same for classes and structs. Now, for something a bit more hairy: Simendsjo's version and mine are not strictly equivalent: - his version is simpler to type and to reason about. You should use it, it's the D way to do this kind of thing. - mine (the two level templates) gets an interesting effect: I can use the first level only (getting the function name), keeping the second level for later: // mine alias timer!foo tfoo; // tfoo is the inner template, the function template /* a bit later */ tfoo(args1); tfoo(args2); import std.algorithm; Args[] argsArray; auto m = map!(tfoo)(argsArray); // applying tfoo on all arguments groups // Simendsjo: timer!foo(args1); timer!foo(args2); // You must provide 'foo' for each call.Also, I am not entirely sure why I need to write "alias F" instead ofjust "F", any explanation would be appreciated. Because in your case, you want to get the name, the symbol. So use an alias parameter. 'F' would be to deal with types, as Ali said. For example: auto foo(F, Args...)(F fn, Args args) { ... } in this case, fn is passed as a runtime value of type F: timer(&foo, args); // the compiler automatically deduces the types of fn and args. Philippe
Jun 23 2012
Thank you all of you for your help! Michael On Sunday, 24 June 2012 at 06:49:38 UTC, Philippe Sigaud wrote:The closest I came to the correct template is template(alias F) timer { auto timer { auto start = Clock.currStdTime(); F(); return Clock.currStdTime() - time; } }The problem with the template is I cannot pass any argument into "F". Howshould I fix this problem? As Simendsjo said, you can use a function template to get what you want and a nicer syntax as the same time. Slightly different code can be obtained by starting from the above code: template timer(alias F) // capture F's name { auto timer(Args...)(Args args) // there are your parameters { import std.datetime; // inner imports auto start = Clock.currStdTime(); F(args); return Clock.currStdTime() - start; } } So it's a template that gets expanded into another template with the same name, a function. Note that the construct: template (T...) { T foo(T t) // some function that depends on the template parameters { } } can get syntax sugar like this: T foo(T...)(T t) { } you can 'fuse' the external template and the inner code to get a function template. The same for classes and structs. Now, for something a bit more hairy: Simendsjo's version and mine are not strictly equivalent: - his version is simpler to type and to reason about. You should use it, it's the D way to do this kind of thing. - mine (the two level templates) gets an interesting effect: I can use the first level only (getting the function name), keeping the second level for later: // mine alias timer!foo tfoo; // tfoo is the inner template, the function template /* a bit later */ tfoo(args1); tfoo(args2); import std.algorithm; Args[] argsArray; auto m = map!(tfoo)(argsArray); // applying tfoo on all arguments groups // Simendsjo: timer!foo(args1); timer!foo(args2); // You must provide 'foo' for each call.Also, I am not entirely sure why I need to write "alias F" instead ofjust "F", any explanation would be appreciated. Because in your case, you want to get the name, the symbol. So use an alias parameter. 'F' would be to deal with types, as Ali said. For example: auto foo(F, Args...)(F fn, Args args) { ... } in this case, fn is passed as a runtime value of type F: timer(&foo, args); // the compiler automatically deduces the types of fn and args. Philippe
Jun 27 2012