www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - template specialization

reply "Larry Luther" <larry.luther dolby.com> writes:
This code:

import std.stdio;


class A {

  void get (T:ubyte)(T[] buffer) {
    writefln( "get (T:ubyte)(T[] buffer)\n");
  }

  void get (T:byte)(T[] buffer) {
    writefln( "get (T:byte)(T[] buffer)\n");
  }

  void get (T)(T[] buffer) {
    writefln( "get (T)(T[] buffer)\n");
  }
}


void main () {
  A foo = new A;
  ubyte[100] ub;
  byte[100] bb;
  int[100] ib;

  foo.get( ub);
  foo.get( bb);
  foo.get( ib);
}

Generates:

  get (T:ubyte)(T[] buffer)

  get (T:ubyte)(T[] buffer)

  get (T)(T[] buffer)

Note:  If "get(T:byte)" preceeded "get(T:ubyte)" then "get(T:byte)" would be 
called in both cases.

Q: Is this the way it's supposed to be?

  Thanks, Larry
Jun 08 2010
next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Larry Luther <larry.luther dolby.com> wrote:

   get (T:ubyte)(T[] buffer)

   get (T:ubyte)(T[] buffer)

   get (T)(T[] buffer)

 Q: Is this the way it's supposed to be?
Looks very much correct, yes. Is there a problem? -- Simen
Jun 08 2010
prev sibling next sibling parent reply Robert Clipsham <robert octarineparrot.com> writes:
On 08/06/10 22:25, Larry Luther wrote:
 Q: Is this the way it's supposed to be?
Yes, byte implicitly casts to ubyte so it's accepted. Try switching the templates round, they will both be byte. The way around this is to add template constraints to the templates: void get(T:ubyte)(T[] buffer) if( is( T == ubyte ) ) { } void get(T:byte)(T[] buffer) if( is( T == byte ) ) { } etc. Hope this helps, Robert
Jun 08 2010
parent Ellery Newcomer <ellery-newcomer utulsa.edu> writes:
On 06/08/2010 05:01 PM, Robert Clipsham wrote:
 On 08/06/10 22:25, Larry Luther wrote:
 Q: Is this the way it's supposed to be?
Yes, byte implicitly casts to ubyte so it's accepted. Try switching the templates round, they will both be byte. The way around this is to add template constraints to the templates: void get(T:ubyte)(T[] buffer) if( is( T == ubyte ) ) { } void get(T:byte)(T[] buffer) if( is( T == byte ) ) { } etc. Hope this helps, Robert
bit odd though, since byte[] isn't implicitly convertible to ubyte[]. no wait! yes it is! void get(T:ubyte[])(T t){} .. get(new byte[](1)); no wait! no it isn't! ubyte[] u = new byte[](1); and is it just me, or does the following silently cast away immutability? get("hi mom!");
Jun 08 2010
prev sibling next sibling parent reply "Larry Luther" <larry.luther dolby.com> writes:
Thanks guys.

  Simen asked:  "Is there a problem?".

  Well, I kind of expected a "ubyte" buffer to be matched with a 
"get(T:ubyte)".
  I thought methods were searched for the "best" match.

  Larry 
Jun 08 2010
parent Don <nospam nospam.com> writes:
Larry Luther wrote:
 Thanks guys.
 
   Simen asked:  "Is there a problem?".
 
   Well, I kind of expected a "ubyte" buffer to be matched with a 
 "get(T:ubyte)".
   I thought methods were searched for the "best" match.
No, C++ does it that way, and it gets horrendously complicated. In D, it has to match exactly.
Jun 08 2010
prev sibling next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 08 Jun 2010 17:25:43 -0400, Larry Luther <larry.luther dolby.com>  
wrote:

 This code:

 import std.stdio;


 class A {

   void get (T:ubyte)(T[] buffer) {
     writefln( "get (T:ubyte)(T[] buffer)\n");
   }

   void get (T:byte)(T[] buffer) {
     writefln( "get (T:byte)(T[] buffer)\n");
   }

   void get (T)(T[] buffer) {
     writefln( "get (T)(T[] buffer)\n");
   }
 }


 void main () {
   A foo = new A;
   ubyte[100] ub;
   byte[100] bb;
   int[100] ib;

   foo.get( ub);
   foo.get( bb);
   foo.get( ib);
 }

 Generates:

   get (T:ubyte)(T[] buffer)

   get (T:ubyte)(T[] buffer)

   get (T)(T[] buffer)

 Note:  If "get(T:byte)" preceeded "get(T:ubyte)" then "get(T:byte)"  
 would be
 called in both cases.

 Q: Is this the way it's supposed to be?

   Thanks, Larry
Here is your mistake: T:U as defined by the spec means any T that implicitly casts to U, not a T that exactly equals U. Since ubyte and byte implicitly cast to eachother, the first template matches, no matter the order. But there is a more subtle mistake in what you are doing. The mistake is here:
 void get (T:ubyte)(T[] buffer) {
   writefln( "get (T:ubyte)(T[] buffer)\n");
 }
You are assuming that because of this printout, the same instantiation is used. BUT... The instantiations are different! You should try this instead:
 void get (T:ubyte)(T[] buffer) {
   writefln( "get (T:ubyte)(T[] buffer), T == %s\n", T.stringof);
 }
What you will find is the first template is used, but the template parameter T is correctly byte or ubyte depending on the call. To do what you really want, use template constraints as Robert has suggested. Before template constraints, the only way to do this properly is to use a static if. I should also mention that a planned enhancement for the compiler is to make it so this kind of junk isn't necessary, you should just be able to do this:
   void get (ubyte[] buffer) {
   }

   void get (byte[] buffer) {
   }

   void get (T)(T[] buffer) {
   }
I know this is planned, because it's in TDPL. BTW, are there any bug reports for this? -Steve
Jun 09 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Steven Schveighoffer:
 I know this is planned, because it's in TDPL.  BTW, are there any bug  
 reports for this?
Please write one, overloading of functions with templates is an important and basic thing. Bye, bearophile
Jun 09 2010
parent Trass3r <un known.com> writes:
 Please write one, overloading of functions with templates is an  
 important and basic thing.
http://d.puremagic.com/issues/show_bug.cgi?id=3941
Jun 09 2010
prev sibling parent "Larry Luther" <larry.luther dolby.com> writes:
Thanks everyone. 
Jun 10 2010