www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Where does the template parameter E come from?

reply simendsjo <simen.endsjo pandavre.com> writes:
When running compose with two arguments, the implementation uses the 
template parameter E. I don't understand what's going on here as E isn't 
submitted to the template - what type is E?
I've also seen this in unary/binaryFun using ElementType.


template compose(fun...) { alias composeImpl!(fun).doIt compose; }

// Implementation of compose
template composeImpl(fun...)
{
     static if (fun.length == 1)
     {
         static if (is(typeof(fun[0]) : string))
             alias unaryFun!(fun[0]) doIt;
         else
             alias fun[0] doIt;
     }
     else static if (fun.length == 2)
     {
         // starch
         static if (is(typeof(fun[0]) : string))
             alias unaryFun!(fun[0]) fun0;
         else
             alias fun[0] fun0;
         static if (is(typeof(fun[1]) : string))
             alias unaryFun!(fun[1]) fun1;
         else
             alias fun[1] fun1;
         // protein: the core composition operation
         typeof({ E a; return fun0(fun1(a)); }()) doIt(E)(E a)
         {
             return fun0(fun1(a));
         }
     }
     else
     {
         // protein: assembling operations
         alias composeImpl!(fun[0], composeImpl!(fun[1 .. $]).doIt).doIt 
doIt;
     }
}
Mar 28 2011
next sibling parent simendsjo <simen.endsjo pandavre.com> writes:
On 28.03.2011 16:54, simendsjo wrote:
 When running compose with two arguments, the implementation uses the
 template parameter E. I don't understand what's going on here as E isn't
 submitted to the template - what type is E?
 I've also seen this in unary/binaryFun using ElementType.


 template compose(fun...) { alias composeImpl!(fun).doIt compose; }

 // Implementation of compose
 template composeImpl(fun...)
 {
 static if (fun.length == 1)
 {
 static if (is(typeof(fun[0]) : string))
 alias unaryFun!(fun[0]) doIt;
 else
 alias fun[0] doIt;
 }
 else static if (fun.length == 2)
 {
 // starch
 static if (is(typeof(fun[0]) : string))
 alias unaryFun!(fun[0]) fun0;
 else
 alias fun[0] fun0;
 static if (is(typeof(fun[1]) : string))
 alias unaryFun!(fun[1]) fun1;
 else
 alias fun[1] fun1;
 // protein: the core composition operation
 typeof({ E a; return fun0(fun1(a)); }()) doIt(E)(E a)
 {
 return fun0(fun1(a));
 }
 }
 else
 {
 // protein: assembling operations
 alias composeImpl!(fun[0], composeImpl!(fun[1 .. $]).doIt).doIt doIt;
 }
 }

I think I get it. doIt becomes the function being called. So E is the type of the parameter being used when calling compose.
Mar 28 2011
prev sibling parent reply David Nadlinger <see klickverbot.at> writes:
On 3/28/11 4:54 PM, simendsjo wrote:
 When running compose with two arguments, the implementation uses the
 template parameter E. I don't understand what's going on here as E isn't
 submitted to the template - what type is E?
 […]
 typeof({ E a; return fun0(fun1(a)); }()) doIt(E)(E a)
 {  […] }

doIt is a function template, so E will be deduced to be whatever type the passed argument is – you won't notice the extra »template layer« as E is automatically inferred from the argument. For better understanding, you might want to look at the definition like this: --- template composeImpl(fun...) { […] template doIt(E) { typeof({ E a; return fun0(fun1(a)); }()) doIt(E a) { […] } } } --- David
Mar 28 2011
parent reply simendsjo <simen.endsjo pandavre.com> writes:
On 28.03.2011 17:07, David Nadlinger wrote:
 On 3/28/11 4:54 PM, simendsjo wrote:
 When running compose with two arguments, the implementation uses the
 template parameter E. I don't understand what's going on here as E isn't
 submitted to the template - what type is E?
 […]
 typeof({ E a; return fun0(fun1(a)); }()) doIt(E)(E a)
 { […] }

doIt is a function template, so E will be deduced to be whatever type the passed argument is – you won't notice the extra »template layer« as E is automatically inferred from the argument. For better understanding, you might want to look at the definition like this: --- template composeImpl(fun...) { […] template doIt(E) { typeof({ E a; return fun0(fun1(a)); }()) doIt(E a) { […] } } } --- David

Thanks. That seems like a good way of mentally mapping template usage until it comes more naturally.
Mar 28 2011
parent David Nadlinger <see klickverbot.at> writes:
On 3/28/11 5:14 PM, simendsjo wrote:
 On 28.03.2011 17:07, David Nadlinger wrote:
 On 3/28/11 4:54 PM, simendsjo wrote:
 When running compose with two arguments, the implementation uses the
 template parameter E. I don't understand what's going on here as E isn't
 submitted to the template - what type is E?
 […]
 typeof({ E a; return fun0(fun1(a)); }()) doIt(E)(E a)
 { […] }

doIt is a function template, so E will be deduced to be whatever type the passed argument is – you won't notice the extra »template layer« as E is automatically inferred from the argument. For better understanding, you might want to look at the definition like this: --- template composeImpl(fun...) { […] template doIt(E) { typeof({ E a; return fun0(fun1(a)); }()) doIt(E a) { […] } } } --- David

Thanks. That seems like a good way of mentally mapping template usage until it comes more naturally.

Even more, due to the eponymous template »trick«, there is almost no difference between the forms – with the important exception being that function templates enjoy IFTI (implicit function template instantiation), the feature which allows you to omit the type parameter(s) if it can be deduced from the arguments. David
Mar 28 2011