Thread overview
Template function specialization doesn't work
Jul 07, 2020
IGotD-
Jul 07, 2020
IGotD-
Jul 07, 2020
IGotD-
Jul 07, 2020
IGotD-
Jul 07, 2020
Ali Çehreli
July 07, 2020
I have two template functions

void overloadedFunction(T)(ref T val)
{
...
}
	
	
void overloadedFunction(T : T[])(ref T[] s)
{
...
}

Obviously the second should be used when the parameter is a slice of any type, and the first should be used in other cases. However this doesn't happen, the compiler always picks the first function regardless if the parameter is a slice or not.

So

ubyte[3] ar = [ 1, 2, 3 ];
ubyte[] arSlice = ar;

overloadedFunction(arSlice);

The first function will be used. Shouldn't the template argument (T : T[]) make the compiler pick the second one?

July 07, 2020
On Tuesday, 7 July 2020 at 19:53:30 UTC, IGotD- wrote:
>
>...
>

I also forgot to mention that the overloadedFunction is used in a variadic template function.

void processAll(T...)(ref T t)
{
    foreach(ref v; t)
    {
        overloadedFunction(v);
    }
}



July 07, 2020
On 7/7/20 3:53 PM, IGotD- wrote:
> I have two template functions
> 
> void overloadedFunction(T)(ref T val)
> {
> ....
> }
> 
> 
> void overloadedFunction(T : T[])(ref T[] s)
> {
> ....
> }
> 
> Obviously the second should be used when the parameter is a slice of any type, and the first should be used in other cases. However this doesn't happen, the compiler always picks the first function regardless if the parameter is a slice or not.
> 
> So
> 
> ubyte[3] ar = [ 1, 2, 3 ];
> ubyte[] arSlice = ar;
> 
> overloadedFunction(arSlice);
> 
> The first function will be used. Shouldn't the template argument (T : T[]) make the compiler pick the second one?
> 

That specialization is... odd. It's basically saying, is T an array of T.

I know I've seen this before, so I think it's valid. But maybe not?

Have you tried (T: U[], U)(ref T[] s) ?

-Steve
July 07, 2020
On 7/7/20 4:04 PM, Steven Schveighoffer wrote:

> Have you tried (T: U[], U)(ref T[] s) ?

Ugh... (T: U[], U)(ref T s)

-Steve
July 07, 2020
On Tuesday, 7 July 2020 at 20:05:37 UTC, Steven Schveighoffer wrote:
> On 7/7/20 4:04 PM, Steven Schveighoffer wrote:
>
>> Have you tried (T: U[], U)(ref T[] s) ?
>
> Ugh... (T: U[], U)(ref T s)
>
> -Steve

Thank you, that worked and now it picked the correct overloaded function. I don't understand why and it is a bit counter intuitive. Why two template arguments as I'm not even us using U?

If you look at the article

https://dlang.org/articles/templates-revisited.html#specialization

Then it mentioned that (T : T*) would work. Intuitively, then you would think (T : T[]) would work.
July 07, 2020
On Tuesday, 7 July 2020 at 20:14:19 UTC, IGotD- wrote:
>
> Thank you, that worked and now it picked the correct overloaded function. I don't understand why and it is a bit counter intuitive. Why two template arguments as I'm not even us using U?
>
> If you look at the article
>
> https://dlang.org/articles/templates-revisited.html#specialization
>
> Then it mentioned that (T : T*) would work. Intuitively, then you would think (T : T[]) would work.

Here (T : T[]) is even the example with the correct double[] type as a correct example as well.

https://dlang.org/spec/template.html#parameters_specialization

I'm confused.
July 07, 2020
On 7/7/20 4:21 PM, IGotD- wrote:
> On Tuesday, 7 July 2020 at 20:14:19 UTC, IGotD- wrote:
>>
>> Thank you, that worked and now it picked the correct overloaded function. I don't understand why and it is a bit counter intuitive. Why two template arguments as I'm not even us using U?
>>
>> If you look at the article
>>
>> https://dlang.org/articles/templates-revisited.html#specialization
>>
>> Then it mentioned that (T : T*) would work. Intuitively, then you would think (T : T[]) would work.
> 
> Here (T : T[]) is even the example with the correct double[] type as a correct example as well.
> 
> https://dlang.org/spec/template.html#parameters_specialization
> 
> I'm confused.

That's not IFTI, that's template instantiation.

I bet if you did:

overloadedFunction!(ubyte[])(arSlice)

it would pick the second one.

there is some extra magic going on for IFTI, and I'm not sure how it figures out what to do. I would agree with you that if explicit templates use that rule, so should IFTI. But perhaps there's a good reason why it can't be done.

So possibly:

overloadedFunction(arSlice) => Pattern match `ref T[]` to `ubyte[]` => T is ubyte => Check ubyte for T : T[], no match.

-Steve
July 07, 2020
On 7/7/20 12:53 PM, IGotD- wrote:

> ubyte[3] ar = [ 1, 2, 3 ];
> ubyte[] arSlice = ar;
> 
> overloadedFunction(arSlice);
> 
> The first function will be used. Shouldn't the template argument (T : T[]) make the compiler pick the second one?

There is also template constraints which may be useful:

import std.traits;

void overloadedFunction(T)(ref T val)
if (!isArray!T) {
  writeln("general");
}

void overloadedFunction(T)(ref T s)
if (isArray!T) {
  writeln("T[]");
}

Ali