digitalmars.D - template auto value
- Jonathan Marler (52/52) Mar 02 2018 I believe I found small hole in template parameter semantics.
- H. S. Teoh (24/26) Mar 02 2018 Not true:
- Timon Gehr (5/22) Mar 02 2018 No, it fails because a "symbol" is expected, not a basic type. There
- Jonathan Marler (4/28) Mar 02 2018 Ah thank you...I guess I didn't realize that literals like 1 and
- Steven Schveighoffer (10/48) Mar 05 2018 Well, they aren't. But template alias is a bit of a mess when it comes
- Jonathan Marler (9/59) Mar 05 2018 Thanks for the tip, it looks like the spec does mention
I believe I found small hole in template parameter semantics. I've summarized it here (https://github.com/marler8997/dlangfeatures#template-auto-value-parameter). Wanted to get feedback before I look into creating a PR for it. ---------------------------------- COPY/PASTED from https://github.com/marler8997/dlangfeatures#template-auto-value-parameter ---------------------------------- If you reference the D grammar for templates (See https://dlang.org/spec/template.html), there are currently 5 categories of template parameters: TemplateParameter: TemplateTypeParameter TemplateValueParameter TemplateAliasParameter TemplateSequenceParameter TemplateThisParameter However there is a hole in this list, namely, generic template value parameters. The current TemplateValueParameter grammar node must explicitly declare a "BasicType": TemplateValueParameter: BasicType Declarator BasicType Declarator TemplateValueParameterSpecialization BasicType Declarator TemplateValueParameterDefault BasicType Declarator TemplateValueParameterSpecialization TemplateValueParameterDefault For example: --- template foo(string value) { } foo!"hello"; --- However, you can't create a template that accepts a value of any type. This would a good use case for the auto keyword, i.e. --- template foo(auto value) { } foo!0; foo!"hello"; --- This would be a simple change to the grammar, namely, BasicTemplateType: BasicType auto TemplateValueParameter: BasicTemplateType Declarator BasicTemplateType Declarator TemplateValueParameterSpecialization BasicTemplateType Declarator TemplateValueParameterDefault BasicTemplateType Declarator TemplateValueParameterSpecialization TemplateValueParameterDefault
Mar 02 2018
On Fri, Mar 02, 2018 at 11:51:08PM +0000, Jonathan Marler via Digitalmars-d wrote:I believe I found small hole in template parameter semantics. [...] you can't create a template that accepts a value of any type.Not true: template counterexample(alias T) {} int x; string s; alias U = counterexample!x; // OK alias V = counterexample!1; // OK alias W = counterexample!"yup"; // OK alias X = counterexample!s; // OK alias Z = counterexample!int; // NG The last one fails because a value is expected, not a type. If you *really* want to accept both values and types, `...` comes to the rescue: template rescue(T...) if (T.length == 1) {} int x; string s; alias U = rescue!x; // OK alias V = rescue!1; // OK alias W = rescue!"yup"; // OK alias X = rescue!s; // OK alias Z = rescue!int; // OK! T -- In a world without fences, who needs Windows and Gates? -- Christian Surchi
Mar 02 2018
On 03.03.2018 01:20, H. S. Teoh wrote:On Fri, Mar 02, 2018 at 11:51:08PM +0000, Jonathan Marler via Digitalmars-d wrote:No, it fails because a "symbol" is expected, not a basic type. There really is no good reason why int should not be accepted -- a class or struct type would be accepted. IIRC Walter has agreed to this, and it's just pending implementation.I believe I found small hole in template parameter semantics. [...] you can't create a template that accepts a value of any type.Not true: template counterexample(alias T) {} int x; string s; alias U = counterexample!x; // OK alias V = counterexample!1; // OK alias W = counterexample!"yup"; // OK alias X = counterexample!s; // OK alias Z = counterexample!int; // NG The last one fails because a value is expected, not a type.
Mar 02 2018
On Saturday, 3 March 2018 at 00:20:14 UTC, H. S. Teoh wrote:On Fri, Mar 02, 2018 at 11:51:08PM +0000, Jonathan Marler via Digitalmars-d wrote:Ah thank you...I guess I didn't realize that literals like 1 and "yup" were considered "symbols" when it comes to alias template parameters.[...]Not true: template counterexample(alias T) {} int x; string s; alias U = counterexample!x; // OK alias V = counterexample!1; // OK alias W = counterexample!"yup"; // OK alias X = counterexample!s; // OK alias Z = counterexample!int; // NG The last one fails because a value is expected, not a type. If you *really* want to accept both values and types, `...` comes to the rescue: template rescue(T...) if (T.length == 1) {} int x; string s; alias U = rescue!x; // OK alias V = rescue!1; // OK alias W = rescue!"yup"; // OK alias X = rescue!s; // OK alias Z = rescue!int; // OK! T
Mar 02 2018
On 3/2/18 8:49 PM, Jonathan Marler wrote:On Saturday, 3 March 2018 at 00:20:14 UTC, H. S. Teoh wrote:Well, they aren't. But template alias is a bit of a mess when it comes to the spec. It will accept anything except keywords AFAIK. Would be nice if it just worked like the variadic version. The variadic version is what is usually needed (you see a lot of if(T.length == 1) in std.traits). But, if you wanted to ensure values (which is more akin to your proposal), you can do: template rescue(alias val) if(!is(val)) // not a type -SteveOn Fri, Mar 02, 2018 at 11:51:08PM +0000, Jonathan Marler via Digitalmars-d wrote:Ah thank you...I guess I didn't realize that literals like 1 and "yup" were considered "symbols" when it comes to alias template parameters.[...]Not true: template counterexample(alias T) {} int x; string s; alias U = counterexample!x; // OK alias V = counterexample!1; // OK alias W = counterexample!"yup"; // OK alias X = counterexample!s; // OK alias Z = counterexample!int; // NG The last one fails because a value is expected, not a type. If you *really* want to accept both values and types, `...` comes to the rescue: template rescue(T...) if (T.length == 1) {} int x; string s; alias U = rescue!x; // OK alias V = rescue!1; // OK alias W = rescue!"yup"; // OK alias X = rescue!s; // OK alias Z = rescue!int; // OK! T
Mar 05 2018
On Monday, 5 March 2018 at 13:03:50 UTC, Steven Schveighoffer wrote:On 3/2/18 8:49 PM, Jonathan Marler wrote:Thanks for the tip, it looks like the spec does mention "literals" but "alias" parameters are even more versatile than that (https://dlang.org/spec/template.html#TemplateAliasParameter). For example you can pass a function call. I've created an issue to make sure we update the spec to reflect the true capabilities: https://issues.dlang.org/show_bug.cgi?id=18558On Saturday, 3 March 2018 at 00:20:14 UTC, H. S. Teoh wrote:Well, they aren't. But template alias is a bit of a mess when it comes to the spec. It will accept anything except keywords AFAIK. Would be nice if it just worked like the variadic version. The variadic version is what is usually needed (you see a lot of if(T.length == 1) in std.traits). But, if you wanted to ensure values (which is more akin to your proposal), you can do: template rescue(alias val) if(!is(val)) // not a type -SteveOn Fri, Mar 02, 2018 at 11:51:08PM +0000, Jonathan Marler via Digitalmars-d wrote:Ah thank you...I guess I didn't realize that literals like 1 and "yup" were considered "symbols" when it comes to alias template parameters.[...]Not true: template counterexample(alias T) {} int x; string s; alias U = counterexample!x; // OK alias V = counterexample!1; // OK alias W = counterexample!"yup"; // OK alias X = counterexample!s; // OK alias Z = counterexample!int; // NG The last one fails because a value is expected, not a type. If you *really* want to accept both values and types, `...` comes to the rescue: template rescue(T...) if (T.length == 1) {} int x; string s; alias U = rescue!x; // OK alias V = rescue!1; // OK alias W = rescue!"yup"; // OK alias X = rescue!s; // OK alias Z = rescue!int; // OK! T
Mar 05 2018