www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - D2: Template as an alias to another template instance

reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
Hello,

I'm trying to make a template that would be an alias to another template 
instance (sort of a shortcut), but I'm having some difficulties. 
Consider this code:

---

import std.stdio;

struct Templ(int N,T){}

alias Templ!(1,float) Templ1f;

template Templ1(T)
{	
	alias Templ!(1,T) Templ1;
}

void foo1(T)(Templ!(1,T) t){}

void foo2(T)(Templ1!T t){}

void main()
{
	Templ1f t1f;
	Templ1!(float) t1f1;
	foo1(t1f);
	foo2(t1f1); // this doesn't compile
	// foo2(t1f); // this won't compile either
}

---

Unfortunately, dmd 2.032 on Windows and 2.037 on Linux both give me this 
error:

---

templ.d(21): Error: template templ.foo2(T) does not match any function 
template declaration
templ.d(21): Error: template templ.foo2(T) cannot deduce template 
function from argument types !()(Templ!(1,float))

---

I had an impression that aliasing employed in Templ1 would effectively 
make Templ1 work as a type (a shortcut to Templ!(1,T)), but I don't get 
this behvior.
Now, I'm not lazy to declare functions with parameters having full 
template instance names. It's just that sometimes function declaration 
will be obvious (or at least cleaner) if its parameters have shorter but 
meaningful type names instead of generic name with a set of properties 
(that is, a template name with a full set of template parameters).

Is there something wrong with my code, am I missing something perhaps?
Dec 24 2009
next sibling parent =?ISO-8859-1?Q?Tomek_Sowi=f1ski?= <just ask.me> writes:
Stanislav Blinov Wrote:

 Hello,
 
 I'm trying to make a template that would be an alias to another template 
 instance (sort of a shortcut), but I'm having some difficulties. 
 Consider this code:
 
 ---
 
 import std.stdio;
 
 struct Templ(int N,T){}
 
 alias Templ!(1,float) Templ1f;
 
 template Templ1(T)
 {	
 	alias Templ!(1,T) Templ1;
 }
 
 void foo1(T)(Templ!(1,T) t){}
 
 void foo2(T)(Templ1!T t){}
 
 void main()
 {
 	Templ1f t1f;
 	Templ1!(float) t1f1;
 	foo1(t1f);
 	foo2(t1f1); // this doesn't compile
 	// foo2(t1f); // this won't compile either
 }
 
 ---
 
 Unfortunately, dmd 2.032 on Windows and 2.037 on Linux both give me this 
 error:
 
 ---
 
 templ.d(21): Error: template templ.foo2(T) does not match any function 
 template declaration
 templ.d(21): Error: template templ.foo2(T) cannot deduce template 
 function from argument types !()(Templ!(1,float))
 
 ---
 
 I had an impression that aliasing employed in Templ1 would effectively 
 make Templ1 work as a type (a shortcut to Templ!(1,T)), but I don't get 
 this behvior.
 Now, I'm not lazy to declare functions with parameters having full 
 template instance names. It's just that sometimes function declaration 
 will be obvious (or at least cleaner) if its parameters have shorter but 
 meaningful type names instead of generic name with a set of properties 
 (that is, a template name with a full set of template parameters).
 
 Is there something wrong with my code, am I missing something perhaps?
To my eye it is a compiler bug. Tomek
Dec 24 2009
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 24 Dec 2009 12:45:41 -0500, Stanislav Blinov  
<stanislav.blinov gmail.com> wrote:

 Hello,

 I'm trying to make a template that would be an alias to another template  
 instance (sort of a shortcut), but I'm having some difficulties.  
 Consider this code:

 ---

 import std.stdio;

 struct Templ(int N,T){}

 alias Templ!(1,float) Templ1f;

 template Templ1(T)
 {	
 	alias Templ!(1,T) Templ1;
 }

 void foo1(T)(Templ!(1,T) t){}

 void foo2(T)(Templ1!T t){}

 void main()
 {
 	Templ1f t1f;
 	Templ1!(float) t1f1;
 	foo1(t1f);
 	foo2(t1f1); // this doesn't compile
 	// foo2(t1f); // this won't compile either
 }

 ---

 Unfortunately, dmd 2.032 on Windows and 2.037 on Linux both give me this  
 error:

 ---

 templ.d(21): Error: template templ.foo2(T) does not match any function  
 template declaration
 templ.d(21): Error: template templ.foo2(T) cannot deduce template  
 function from argument types !()(Templ!(1,float))

 ---

 I had an impression that aliasing employed in Templ1 would effectively  
 make Templ1 work as a type (a shortcut to Templ!(1,T)), but I don't get  
 this behvior.
 Now, I'm not lazy to declare functions with parameters having full  
 template instance names. It's just that sometimes function declaration  
 will be obvious (or at least cleaner) if its parameters have shorter but  
 meaningful type names instead of generic name with a set of properties  
 (that is, a template name with a full set of template parameters).

 Is there something wrong with my code, am I missing something perhaps?
The issue is that the compiler has trouble deducing how to construct the right template from the arguments. Implicit Function Template Instantiation (IFTI) works only on direct template instantiations, going through aliases is difficult because it cannot figure out how to get from A to B. There is an open bugzilla that might fix this: http://d.puremagic.com/issues/show_bug.cgi?id=1807 Taking your example foo1, the compiler is given a struct Templ1!(float), but it has to match argument Templ!(1, T). A person can see that if you plug in float for T, you get to the same result, but this sort of backwards deduction doesn't exist in the compiler. Because the template can contain *anything*, i.e. you could have something like this: template Templ1(T) { static if(is(T == int)) alias Templ!(1, float) Templ1; else alias Templ!(1, int) Templ1; } If templ1 looked like this, how would the compiler deduce that it has to plug in 'int' for T in order to get the right result? The proposed solution in bug 1807 says that in the most simple cases where the template is just an alias, the compiler should reduce the template argument type to the alias. Even with this fix, my insane example wouldn't work with IFTI :) I think there is a lot more work that can be done on IFTI, and it's probably low on the todo list because it's not critical to get done before the book comes out. -Steve
Dec 28 2009
parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
Steven Schveighoffer wrote:

[irrelevant text cut out]
 ...I'm having some difficulties. Consider this code:
 ---
 struct Templ(int N,T){}

 template Templ1(T)
 {   
     alias Templ!(1,T) Templ1;
 }

 void foo2(T)(Templ1!T t){}

 void main()
 {
     Templ1!(float) t1f1;
     foo2(t1f1); // this doesn't compile
 }
 ---
 templ.d(21): Error: template templ.foo2(T) does not match any function 
 template declaration
 templ.d(21): Error: template templ.foo2(T) cannot deduce template 
 function from argument types !()(Templ!(1,float))
 ---
 Is there something wrong with my code, am I missing something perhaps?
The issue is that the compiler has trouble deducing how to construct the right template from the arguments. Taking your example foo1, the compiler is given a struct Templ1!(float), but it has to match argument Templ!(1, T). A person can see that if you plug in float for T, you get to the same result, but this sort of backwards deduction doesn't exist in the compiler.
Yeah, the error message issued by the compiler that contained type name sort of confused me, because I couldn't understand how the compiler that knows the type is float cannot deduce this float :)
 Because the template 
 can contain *anything*, i.e. you could have something like this:
 
 template Templ1(T)
 {
   static if(is(T == int))
      alias Templ!(1, float) Templ1;
   else
      alias Templ!(1, int) Templ1;
 }
That's one mean example. But it demonstrates the point right to the core. I actually came up with similar one myself while I was trying to figure out a workaround after my initial post, and that was when I realized life's not so easy with this case. Though I didn't quite get exactly why it doesn't work. Now after your explanation I finally got the point.
 
 If templ1 looked like this, how would the compiler deduce that it has to 
 plug in 'int' for T in order to get the right result?  The proposed 
 solution in bug 1807 says that in the most simple cases where the 
 template is just an alias, the compiler should reduce the template 
 argument type to the alias.  Even with this fix, my insane example 
 wouldn't work with IFTI :)
 
 I think there is a lot more work that can be done on IFTI, and it's 
 probably low on the todo list because it's not critical to get done 
 before the book comes out.
Well, that's sad, but what one can do?.. For now, I'll have to live with that I guess, despite my function declarations will be a total mess :) Thanks a lot for your reply and explanation, Steven. I think I should force myself to stand in compiler shoes more often. And thanks Tomek, for pointing out about 'bug'. Your quick response somewhat relieved me of the itchy thought that it was I who made something terribly wrong (well, actually I see that it was wrong in a way - I just demanded too much from the compiler).
Dec 28 2009