www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - template alias that includes a parameter

reply Anonymouse <asdf asdf.net> writes:
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?
Jun 30 2018
next sibling parent Timoses <timosesu gmail.com> writes:
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); }
Jun 30 2018
prev sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
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
Jun 30 2018
parent reply Timoses <timosesu gmail.com> writes:
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
Jul 01 2018
parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
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
Jul 01 2018
parent reply Timoses <timosesu gmail.com> writes:
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
Jul 01 2018
parent Timoses <timosesu gmail.com> writes:
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
Jul 01 2018