Thread overview
Where does the template parameter E come from?
Mar 28, 2011
simendsjo
Mar 28, 2011
simendsjo
Mar 28, 2011
David Nadlinger
Mar 28, 2011
simendsjo
Mar 28, 2011
David Nadlinger
March 28, 2011
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;
    }
}
March 28, 2011
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.
March 28, 2011
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
March 28, 2011
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.
March 28, 2011
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