www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Question about Template

reply "Michael" <pongad gmail.com> writes:
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
next sibling parent simendsjo <simendsjo gmail.com> writes:
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,
 Michael
import 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
prev sibling next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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
prev sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
 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? 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 of
just "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
parent "Michael" <pongad gmail.com> writes:
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". How
should 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 of
just "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