Thread overview
template alias that includes a parameter
Jun 30, 2018
Anonymouse
Jun 30, 2018
Timoses
Jul 01, 2018
Simen Kjærås
Jul 01, 2018
Timoses
Jul 01, 2018
Simen Kjærås
Jul 01, 2018
Timoses
Jul 01, 2018
Timoses
June 30, 2018
I have a template that I want to provide easy aliases for, where the aliases includes (partially applies?) a template parameter.


void fooImpl(char token, T)(const T line)
{
    // ...
}

alias quoteFoo(T) = fooImpl!('"', T);
alias singlequoteFoo(T) = fooImpl!('\'', T);

void main()
{
    quoteFoo(`"asdf"`);
    singlequoteFoo(`'asdf'`);
}


...was how I'd imagined it would look.

>onlineapp.d(11): Error: template onlineapp.quoteFoo cannot deduce function from argument types !()(string), candidates are:
>onlineapp.d(6):        onlineapp.quoteFoo(T)

If I manually pass string as a template parameter, like quoteFoo!string("bar") or singlequoteFoo!string("baz"), it works.

Can I do it this way or do I need to write wrapping functions?
June 30, 2018
On Saturday, 30 June 2018 at 21:11:54 UTC, Anonymouse wrote:
> I have a template that I want to provide easy aliases for, where the aliases includes (partially applies?) a template parameter.
>
>
> void fooImpl(char token, T)(const T line)
> {
>     // ...
> }
>
> alias quoteFoo(T) = fooImpl!('"', T);

would be the same as

template quoteFoo(T)
{
    alias quoteFoo = fooImpl!('"', T);
}

There is no "Implicit Function Template Instantiation (IFTI)" (https://dlang.org/spec/template.html#function-templates) here, as that only works for function templates. That means the compiler won't deduce the template parameter type. So that alias would have to be called with

    quoteFoo!string("I'm a quoted sentence.");

> alias singlequoteFoo(T) = fooImpl!('\'', T);
>
> void main()
> {
>     quoteFoo(`"asdf"`);
>     singlequoteFoo(`'asdf'`);
> }
>
>
> ...was how I'd imagined it would look.
>
>>onlineapp.d(11): Error: template onlineapp.quoteFoo cannot deduce function from argument types !()(string), candidates are:
>>onlineapp.d(6):        onlineapp.quoteFoo(T)
>
> If I manually pass string as a template parameter, like quoteFoo!string("bar") or singlequoteFoo!string("baz"), it works.
>
> Can I do it this way or do I need to write wrapping functions?

Instead of using aliases you could instantiate the function and use a function pointer to it (I hope my lingo is correct...).

    auto quoteFooString = &fooImpl!('"', string);

and use it with

    quoteFooString("I'm another quoted sentence.");

I'm trying to find a way to partially apply something to the template like

    //alias quoteFoo = ApplyLeft!(fooImpl, '"', AliasSeq!(int));
    //quoteFoo(3);

so the template fooImpl would only be partly instantiated with a '"', but the second argument would be left for when calling the function.. Unfortunately, above yields the error

    std/meta.d(1232): Error: template instance `Template!'"'` does not match template declaration fooImpl(char token, T)(const T line)

... Hm..


https://run.dlang.io/is/di8zjl

    import std.stdio;

    void fooImpl(char token, T)(const T line)
    {
        writefln("%s%s%s", token, line, token);
    }

    auto quoteFooString = &fooImpl!('"', string);
    auto singlequoteFooString = &fooImpl!('\'', string);

    void main()
    {
        quoteFooString("test quote");
        singlequoteFooString("test single quote");


        import std.meta;
        // std/meta.d(1232): Error: template instance `Template!'"'` does not match template
        //alias quoteFoo = ApplyLeft!(fooImpl, '"');
        //quoteFoo(3);
    }
July 01, 2018
On Saturday, 30 June 2018 at 21:11:54 UTC, Anonymouse wrote:
> I have a template that I want to provide easy aliases for, where the aliases includes (partially applies?) a template parameter.
>
>
> void fooImpl(char token, T)(const T line)
> {
>     // ...
> }
>
> alias quoteFoo(T) = fooImpl!('"', T);
> alias singlequoteFoo(T) = fooImpl!('\'', T);
>
> void main()
> {
>     quoteFoo(`"asdf"`);
>     singlequoteFoo(`'asdf'`);
> }

I'd send you straight to std.meta.ApplyLeft, but it seems to do the wrong thing here, in that it doesn't handle IFTI. This thing does:

void fooImpl(int n, T)(const T line) { }

unittest {
    alias fun = applyLeft!(fooImpl, 3);
    fun(`aaa`);
    applyLeft!(fooImpl, 3)(`aaa`);
}

template applyLeft(alias Fn, T...) {
    auto applyLeft(U...)(U args) {
        return Fn!T(args);
    }
}

--
  Simen
July 01, 2018
On Sunday, 1 July 2018 at 01:48:15 UTC, Simen Kjærås wrote:
>
> I'd send you straight to std.meta.ApplyLeft, but it seems to do the wrong thing here, in that it doesn't handle IFTI. This thing does:
>
> void fooImpl(int n, T)(const T line) { }
>
> unittest {
>     alias fun = applyLeft!(fooImpl, 3);
>     fun(`aaa`);
>     applyLeft!(fooImpl, 3)(`aaa`);
> }
>
> template applyLeft(alias Fn, T...) {
>     auto applyLeft(U...)(U args) {
>         return Fn!T(args);
>     }
> }

Would be nice if std.meta.ApplyLeft did the job here.. Is there no way of achieving that?
It's current implementation looks like this:

template ApplyLeft(alias Template, args...)
{
    alias ApplyLeft(right...) = SmartAlias!(Template!(args, right));
}

private template SmartAlias(T...)
{
    static if (T.length == 1)
    {
        alias SmartAlias = Alias!T;
    }
    else
    {
        alias SmartAlias = AliasSeq!T;
    }
}

Would have to find a way to determine whether Template would resolve to a function or not. Can't find anything in Traits[1] or std.traits[2]. Template inspection looks rather limited : /.

[1]: https://dlang.org/spec/traits.html
[2]: https://dlang.org/phobos/std_traits.html



July 01, 2018
On Sunday, 1 July 2018 at 09:46:55 UTC, Timoses wrote:
> Would be nice if std.meta.ApplyLeft did the job here.. Is there no way of achieving that?
[snip]
> Would have to find a way to determine whether Template would resolve to a function or not. Can't find anything in Traits[1] or std.traits[2]. Template inspection looks rather limited : /.

It is, but for a fairly good reason. This is perfectly valid D:

template foo(int n) {
    static if (n == 0) {
        struct foo {}
    } else static if (n == 1) {
        enum foo = 24;
    } else {
        void foo() {}
    }
}

Given an uninstantiated foo, you can't know if it'll resolve to a function or not, so I guess some version of the template I wrote could be added to Phobos as ApplyLeftFn or something.

--
  Simen
July 01, 2018
On Sunday, 1 July 2018 at 11:55:15 UTC, Simen Kjærås wrote:
> On Sunday, 1 July 2018 at 09:46:55 UTC, Timoses wrote:
>> Would be nice if std.meta.ApplyLeft did the job here.. Is there no way of achieving that?
> [snip]
>> Would have to find a way to determine whether Template would resolve to a function or not. Can't find anything in Traits[1] or std.traits[2]. Template inspection looks rather limited : /.
>
> It is, but for a fairly good reason. This is perfectly valid D:
>
> template foo(int n) {
>     static if (n == 0) {
>         struct foo {}
>     } else static if (n == 1) {
>         enum foo = 24;
>     } else {
>         void foo() {}
>     }
> }
>
> Given an uninstantiated foo, you can't know if it'll resolve to a function or not, so I guess some version of the template I wrote could be added to Phobos as ApplyLeftFn or something.

Aw, okay, then that won't work.

Still, this looks like it should work:

    void foo(F, T)(T param) { writeln("Called with type: ", T.stringof); }
    alias tfoo = ApplyLeft!(foo, int);

    tfoo!string("hi");
    // tfoo("hi"); // Error

July 01, 2018
On Sunday, 1 July 2018 at 13:01:20 UTC, Timoses wrote:
>
> Aw, okay, then that won't work.
>
> Still, this looks like it should work:
>
>     void foo(F, T)(T param) { writeln("Called with type: ", T.stringof); }
>     alias tfoo = ApplyLeft!(foo, int);
>
>     tfoo!string("hi");
>     // tfoo("hi"); // Error

https://issues.dlang.org/show_bug.cgi?id=9365