Thread overview
template auto value
Mar 02, 2018
Jonathan Marler
Mar 03, 2018
H. S. Teoh
Mar 03, 2018
Timon Gehr
Mar 03, 2018
Jonathan Marler
Mar 05, 2018
Jonathan Marler
March 02, 2018
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
March 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
March 03, 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:
>> 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.

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.
March 03, 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:
>> [...]
>
> 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

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.
March 05, 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:
>> On Fri, Mar 02, 2018 at 11:51:08PM +0000, Jonathan Marler via Digitalmars-d wrote:
>>> [...]
>>
>> 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
> 
> 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.

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

-Steve
March 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:
>> 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:
>>>> [...]
>>>
>>> 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
>> 
>> 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.
>
> 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
>
> -Steve

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=18558