Thread overview
Template argument deduction not working with template specialization
Jan 17
Paul
Jan 17
Paul
Jan 17
Paul
January 17
While trying to use template specializations I noticed the argument deductions do not yield the same version as the ones yielded when being explicit.
Example:

> uint a = 1;
> uint[] b = [2];
> TFoo(a);
> TFoo!(uint[])(b);

> void TFoo(T)(T a) {
> 	pragma(msg, "T: " ~ T.stringof);
> }
> 
> void TFoo(T : T[])(T[] a) {
> 	pragma(msg, "T[]: " ~ T.stringof);
> }

I noticed that an automatically deduced TFoo call always yields the first, while TFoo!(uint[]) yields the array version if present, and defaults to the first elsewise.

Am I incorrect in expecting the same behavior when (ab)using argument deduction or does my usage make sense? I tried searching for this combination (deduction & specialization) but couldn't find another forum post / documentation example.
January 17
On 1/17/21 11:22 AM, Paul wrote:
> While trying to use template specializations I noticed the argument deductions do not yield the same version as the ones yielded when being explicit.
> Example:
> 
>> uint a = 1;
>> uint[] b = [2];
>> TFoo(a);
>> TFoo!(uint[])(b);
> 
>> void TFoo(T)(T a) {
>>     pragma(msg, "T: " ~ T.stringof);
>> }
>>
>> void TFoo(T : T[])(T[] a) {
>>     pragma(msg, "T[]: " ~ T.stringof);
>> }
> 
> I noticed that an automatically deduced TFoo call always yields the first, while TFoo!(uint[]) yields the array version if present, and defaults to the first elsewise.
> 
> Am I incorrect in expecting the same behavior when (ab)using argument deduction or does my usage make sense? I tried searching for this combination (deduction & specialization) but couldn't find another forum post / documentation example.

I've always hated that aspect of specialization. I don't really understand why it's valid (how can T be T[]?)

This works:

void TFoo(T : U[], U)(T a)

-Steve
January 17
On Sunday, 17 January 2021 at 16:42:27 UTC, Steven Schveighoffer wrote:
> I've always hated that aspect of specialization. I don't really understand why it's valid (how can T be T[]?)

I totally agree with that, that confuses me as well.

> This works:
>
> void TFoo(T : U[], U)(T a)

Oh cool, that's surprising to say the least. Thanks! This indeed works with argument deduction :)
January 17
On 1/17/21 3:41 PM, Paul wrote:
> On Sunday, 17 January 2021 at 16:42:27 UTC, Steven Schveighoffer wrote:

>> This works:
>>
>> void TFoo(T : U[], U)(T a)
> 
> Oh cool, that's surprising to say the least. Thanks! This indeed works with argument deduction :)

It's basically saying if T matches the pattern U[] for some U (which is actually defined now inside the function), then it's a match (and preferred over the non-specialized template).

-Steve
January 17
I just figured out half of my frustration is caused by a collision between the 'alias this'd template possibillity and the normal one.
For example:

> struct Bar(uint size, V) {
> 	V[size] blup;
> 	alias blup this;
> }
> 
> void foo(S : T[], T)(S a) {
> 	pragma(msg, "first");
> }
> 
> void foo(S : Bar!(T, U), uint T, U)(S a) {
> 	pragma(msg, "second");
> }

> Bar!(2, int) bar;
> foo(bar);

Will cause "called with argument types `(Bar!(2u, int))` matches both:DUB"
(And "undefined identifier `T`DUB", "undefined identifier `U`DUB", but thats a false positive :/)
While removal of either will make it work fine, as would removal of the alias.

Templating:
> The template picked to instantiate is the one that is most specialized that fits the types of the TemplateArgumentList.
Alias this:
> If an aggregate declaration defines an opCmp or opEquals method, it will take precedence to that of the aliased this member.

I was of the impression D only defaulted to the alias when the original implementation of a (member) function was missing / disfunctional. Shouldn't aliasing also follow this logic when using template specializations? (Even though it may not be a member function)