Given the following code:
void proc(T)( T val )
{
printf( "proc:T\n" );
}
void proc(T,U=void)( T[] val )
{
printf( "proc:T[]\n" );
}
void main()
{
proc( 0 );
proc( "abc".dup );
}
I would expect to see:
proc:T
proc:T[]
Because proc:T[] is more specialized and thus should be preferred for the second call. Instead, it prints:
proc:T
proc:T
Interestingly, moving the dummy parameter to the first function:
void proc(T,U=void)( T val )
{
printf( "proc:T\n" );
}
void proc(T)( T[] val )
{
printf( "proc:T[]\n" );
}
void main()
{
proc( 0 );
proc( "abc".dup );
}
Results in the expected behavior:
proc:T
proc:T[]
I can only assume this means that the dummy parameters required to support overloading are considered for determining how specialized a particular function is, even though they are not used in the function parameter list.
Comment #1 by smjg — 2007-11-10T16:13:08Z
I'm not sure what's meant to happen here. Both templates match the argument type, but it could be the template parameters, not the function parameters, that somehow determine which template is the more specific match.
Comment #2 by sean — 2007-11-11T10:15:58Z
The second overload is a more exact match for array parameters. My original bug report shows what the expected behavior is here.
Comment #3 by smjg — 2007-11-11T10:38:30Z
(In reply to comment #2)
> The second overload is a more exact match for array parameters.
There's no such thing as a "more exact match" - either a match is exact or it isn't. In this case, both are exact matches.
> My original bug report shows what the expected behavior is here.
Remarks like that are no use without an indication of how you have come to that conclusion. What statement(s) in the spec are you going by, exactly?
Comment #4 by sean — 2007-11-11T13:37:19Z
[email protected] wrote:
> http://d.puremagic.com/issues/show_bug.cgi?id=1650
>
> ------- Comment #3 from [email protected] 2007-11-11 10:38 -------
> (In reply to comment #2)
>> The second overload is a more exact match for array parameters.
>
> There's no such thing as a "more exact match" - either a match is exact or it
> isn't. In this case, both are exact matches.
Sorry. I meant "more specialized match." This is how C++ behaves, and
I expected D to behave the same way.
>> My original bug report shows what the expected behavior is here.
>
> Remarks like that are no use without an indication of how you have come to that
> conclusion. What statement(s) in the spec are you going by, exactly?
None. By Walter's statement to me in the newsgroup a year or so ago
that D templates would behave this way.
Sean
Comment #5 by sean — 2008-01-15T17:06:56Z
I don't know why the previous reply is said to have come from Sean Chittenden, but no mater. If it helps, I verified that this was a bug before submitting this ticket because the book covers this topic and I wanted to be sure the discussion was correct. I'm adding this comment to clarify the situation because the book is now available and a question or two has come up about the related (currently broken) example.
Comment #6 by bugzilla — 2008-06-13T04:03:15Z
The "most specialized" template selection algorithm works with the template parameters, not the function parameters.
Currently, the only way to make this example work is:
void proc(T, U=void)( T val )
{
printf( "proc:T\n" );
}
void proc(T:U[], U)( T val )
{
printf( "proc:T[]\n" );
}
void main()
{
proc( 0 );
proc( "abc".dup );
}
because (U[],U) is a match for (T,U), but (T,U) is not a match for (U[],U).
Comment #7 by sean — 2008-06-14T12:45:21Z
So are you saying that the wrong function is selected because D doesn't have ADL? And can you explain why the first template is more specialized than the other? Is it simply because it has fewer template parameters?
Comment #8 by bugzilla — 2008-06-15T00:55:30Z
> So are you saying that the wrong function is selected because D doesn't have
ADL?
No, this has nothing whatsoever to do with ADL. Template functions are overloaded based on the template parameters, not the function parameters.
>And can you explain why the first template is more specialized than the
other?
Specialization heirarchy is determined the same way as in C++. Template A is "at least as specialized" as template B if the template parameters of A can be used to call B. In the examples, (T) can call (T,U=void), so it is at least as specialized. But (T,void) cannot call (T), so it is equally or less specialized. Therefore (T) is more specialized.
(I know this is a bit of a bear to slog through.)
Comment #9 by sean — 2008-06-15T11:12:37Z
Okay, I understand the logic, though I'm not sure I understand the reasoning behind it. I would expect the more correct set of function parameters to be chosen among the set of instantiable function templates rather than the reverse.
So it appears this all came up because we currently need to add dummy template parameters to disambiguate between overloads--adding the dummy parameter effectively changes the overload decisions for the set of matching functions. You've changed the equation a bit by making one template a specialization of the other, so the dummy parameter U could be dropped altogether. Given that dummy parameters seem to alter the overloading behavior of a set of functions, I'm hesitant to endorse it as a viable option for overloading template functions. Perhaps this proposed solution should be reconsidered?
Comment #10 by sean — 2008-06-15T11:31:58Z
Oh, I suppose I should mention that the reason this all came up in the first place is because specialization as in your example doesn't work if the parameter is a static array, while my original example does. That's what prompted the design I'd originally chosen.
Comment #11 by sean — 2008-06-15T11:49:24Z
(In reply to comment #9)
> Okay, I understand the logic, though I'm not sure I understand the reasoning
> behind it. I would expect the more correct set of function parameters to be
> chosen among the set of instantiable function templates rather than the
> reverse.
Let me clarify this a bit. My original (incorrect) understanding of "more specialized" related to the amount of 'work' required to make the set of function parameters work for the supplied arguments. For example:
void fn(T)( T val ) {}
void fn(T)( T[] val ) {}
With the above, I would expect the second function to be a better match for array arguments because T represents less of the complete type, since the array specifier "[]" is explicit. Then I added the dummy template parameter so the module would compile.
Comment #12 by witold.baryluk+d — 2010-01-24T21:09:31Z
You should use probably something like this:
void proc(T : T[])(T[] val) {
}
Is there any reason this is still open?
I cheked documentation and there is such snippet:
void Foo(T, U=T*)(T t) { U p; ... }
int x;
Foo(&x); // T is int, U is int*
Well, for me it is strange that comment says "T is int", Foo is specialized and recived T (int), but we give it a pointer. Something really wrong somewhere.
Comment #13 by bugzilla — 2012-01-21T21:39:46Z
I believe the spec and the behavior of the compiler are matching and correct.