Questions to template overload resolution

Jonathan M Davis jmdavisProg at gmx.com
Tue Apr 12 19:30:09 PDT 2011


> 1) T foo(T:SomeClass)(T arg){..}
> It is specified on the main page that this template will match against
> instantiations with a subclass of SomeClass. Will this also duplicate the
> code? Or will the template work similar to the function T foo(SomeClass
> arg){..}? If yes, why should normal functions and function templates
> without type params be separated at all?

Templates are used for code generation, pure and simple. They don't exist 
until you instantiate them (so, for instance, if a template is horribly broken 
and wouldn't compile if you tried to use it, the code will still compile as 
long as the template isn't used), and every time that you instantiate a 
template with a new type, it generates new code. This allows you to do some 
really nice stuff with different versions of stuff for different types, as 
well as stuff like eponymous templates, where you use a template to generate a 
value.

The templated function

T foo(T)(T arg){...}

is really something like

template foo(T)
{
 T foo(T arg) {...}
}

and the template doesn't really exist until it's instantiated, so it's very 
different from a normal function, which would exist regardless of whether it 
was used. And since the function could change considerably depending on the 
template arguments (you can use static ifs and other templates inside the 
function which could cause the instiated template function to be drastically 
different depending on the template arguments, even if the template's 
signature and constraints are the same).

> 
> 2) Why is this an error? Obviously, the second template is a better match.
> 
> What is the rationale for requiring the clumsier f(T:double,U:int)(T a,U b)
> to f()(double a,int b) to allow proper overload resolution?
> 
> import std.stdio;
> 
> T f(T,U)(T a,U b){
> return a;
> }
> T f()(double a,int b){
> return a;
> }
> 
> void main(){
> writeln(f(1.2,1));//error
> }
> test.d(11): Error: template test.f(T,U) f(T,U) matches more than one
> template declaration, test.d(3):f(T,U) and test.d(6):f()

The second template wouldn't even work. Where does the T come from? I'm 
surprised that even compiles far enough to sayt that it can't determine which 
template to use. But even if you did something like

double f(U)(double a, U b)
{
 return a;
}

I expect that it still wouldn't work, because it matches two separate 
templates. I believe that all template overload resolutions are done via the 
template arguments and template constraints and that the function arguments 
don't enter into it at all. The contents of the template are only relevant 
once the template has been instantiated. Remember that the definition of f is 
really something like this

T f(T, U)
{
 T f(T a, U b)
 {
 return ;
 }
}

That outer template must be properly resolved before what's inside the 
template is even brought into consideration.

If you want to do what you're doing, the second template would look something 
more like

T f(T : double, U : int)(T a, U b)
{
 return a;
}

That way, the template overload resolution can be done based on the template 
parameters, not the function's parameters.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list