www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Multiple Template Specialization Types (in D1)?

reply "Nick Sabalausky" <a a.a> writes:
Is there a way to do something like this in D1 without resorting to function 
overloading?:

void Foo(T : char, wchar, dchar)(T arg) {/*code*/} 
Jul 01 2008
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:g4e7bg$20n8$1 digitalmars.com...
 Is there a way to do something like this in D1 without resorting to 
 function overloading?:

 void Foo(T : char, wchar, dchar)(T arg) {/*code*/}
It's not perfect, but: void Foo(T)(T arg) { static assert(is(T == char) || is(T == wchar) || is(T == dchar), "T must be char, wchar, or dchar"); } D2 would let you put that in a template condition, but D1's stuck with a static assert.
Jul 01 2008
parent "Nick Sabalausky" <a a.a> writes:
"Jarrett Billingsley" <kb3ctd2 yahoo.com> wrote in message 
news:g4e7em$2146$1 digitalmars.com...
 "Nick Sabalausky" <a a.a> wrote in message 
 news:g4e7bg$20n8$1 digitalmars.com...
 Is there a way to do something like this in D1 without resorting to 
 function overloading?:

 void Foo(T : char, wchar, dchar)(T arg) {/*code*/}
It's not perfect, but: void Foo(T)(T arg) { static assert(is(T == char) || is(T == wchar) || is(T == dchar), "T must be char, wchar, or dchar"); } D2 would let you put that in a template condition, but D1's stuck with a static assert.
Yea, I had actually tried that. It technically works, but when the assert fails the compiler just gives you the file/line of the static assert itself, and doesn't give any indication of what file/line attempted the failed instantiation of Foo (which would be a nightmare to track down, particularly if Foo was in a library).
Jul 01 2008
prev sibling parent reply BCS <ao pathlink.com> writes:
Reply to Nick,

 Is there a way to do something like this in D1 without resorting to
 function overloading?:
 
 void Foo(T : char, wchar, dchar)(T arg) {/*code*/}
 
public template Foo(T: char) {alias Foo_dwc(T) Foo; } public template Foo(T: wchar) {alias Foo_dwc(T) Foo; } public template Foo(T: dchar) {alias Foo_dwc(T) Foo; } private void Foo_dwc(T)(T arg) { ... }
Jul 01 2008
parent reply "Nick Sabalausky" <a a.a> writes:
"BCS" <ao pathlink.com> wrote in message 
news:55391cb32eba48caa9a02d954116 news.digitalmars.com...
 Reply to Nick,

 Is there a way to do something like this in D1 without resorting to
 function overloading?:

 void Foo(T : char, wchar, dchar)(T arg) {/*code*/}
public template Foo(T: char) {alias Foo_dwc(T) Foo; } public template Foo(T: wchar) {alias Foo_dwc(T) Foo; } public template Foo(T: dchar) {alias Foo_dwc(T) Foo; } private void Foo_dwc(T)(T arg) { ... }
Failed to compile. Not sure if it's a problem with the technique, a typo, an existing compiler bug, or a previously fixed compiler bug. ----- start test1.d ----- public template Foo(T: char) {alias Foo_dwc(T) Foo; } public template Foo(T: wchar) {alias Foo_dwc(T) Foo; } public template Foo(T: dchar) {alias Foo_dwc(T) Foo; } private void Foo_dwc(T)(T arg) { } void main(char[][] args) { Foo('a'); } ----- end test1.d ----- ----- start compiler output: DMD win 1.029 ----- test1.d(1): semicolon expected to close alias declaration test1.d(1): no identifier for declarator Foo test1.d(2): semicolon expected to close alias declaration test1.d(2): no identifier for declarator Foo test1.d(3): semicolon expected to close alias declaration test1.d(3): no identifier for declarator Foo ----- end compiler output: DMD win 1.029 ----- Just for the hell of it, I tried changing all three "alias Foo_dwc(T) Foo;" to "alias Foo_dwc!(T) Foo;" (ie, added "!"): ----- start test2.d ----- public template Foo(T: char) {alias Foo_dwc!(T) Foo; } public template Foo(T: wchar) {alias Foo_dwc!(T) Foo; } public template Foo(T: dchar) {alias Foo_dwc!(T) Foo; } private void Foo_dwc(T)(T arg) { } void main(char[][] args) { Foo('a'); } ----- end test2.d ----- ----- start compiler output: DMD win 1.029 ----- test2.d(1): template test2.Foo(T : char) is not a function template test2.d(9): template test2.Foo(T : char) cannot deduce template function from argument types (char) ----- end compiler output: DMD win 1.029 -----
Jul 01 2008
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:g4ejen$10a$1 digitalmars.com...

 Just for the hell of it, I tried changing all three "alias Foo_dwc(T) 
 Foo;" to "alias Foo_dwc!(T) Foo;" (ie, added "!"):

 ----- start test2.d -----
 public template Foo(T: char)  {alias Foo_dwc!(T) Foo; }
 public template Foo(T: wchar) {alias Foo_dwc!(T) Foo; }
 public template Foo(T: dchar) {alias Foo_dwc!(T) Foo; }

 private void Foo_dwc(T)(T arg) {  }

 void main(char[][] args)
 {
 Foo('a');
 }
Right, the bangs are necessary.
 ----- end test2.d -----
 ----- start compiler output: DMD win 1.029 -----
 test2.d(1): template test2.Foo(T : char) is not a function template
 test2.d(9): template test2.Foo(T : char) cannot deduce template function 
 from argument types (char)
 ----- end compiler output: DMD win 1.029 -----
And this is the sad outcome -- once you do this, Foo is no longer a function template, and so it can't have IFTI performed on it. *sigh*
Jul 01 2008
parent reply "Nick Sabalausky" <a a.a> writes:
"Jarrett Billingsley" <kb3ctd2 yahoo.com> wrote in message 
news:g4es21$l49$1 digitalmars.com...
 "Nick Sabalausky" <a a.a> wrote in message 
 news:g4ejen$10a$1 digitalmars.com...

 Just for the hell of it, I tried changing all three "alias Foo_dwc(T) 
 Foo;" to "alias Foo_dwc!(T) Foo;" (ie, added "!"):

 ----- start test2.d -----
 public template Foo(T: char)  {alias Foo_dwc!(T) Foo; }
 public template Foo(T: wchar) {alias Foo_dwc!(T) Foo; }
 public template Foo(T: dchar) {alias Foo_dwc!(T) Foo; }

 private void Foo_dwc(T)(T arg) {  }

 void main(char[][] args)
 {
 Foo('a');
 }
Right, the bangs are necessary.
 ----- end test2.d -----
 ----- start compiler output: DMD win 1.029 -----
 test2.d(1): template test2.Foo(T : char) is not a function template
 test2.d(9): template test2.Foo(T : char) cannot deduce template function 
 from argument types (char)
 ----- end compiler output: DMD win 1.029 -----
And this is the sad outcome -- once you do this, Foo is no longer a function template, and so it can't have IFTI performed on it. *sigh*
I'm still somewhat new to D's templates (been spending a lot of time in non-D development...not by choice), so I'm trying to understand exactly what's going on here as best as I can. Looked up "IFTI" (Implicit Function Template Instantiation), so I see now this method (test2.d) does work, but you have to explicitly instantiate the Foo template when calling the function: In main: "Foo('a');" -> "Foo!(char)('a');" That works. The first compiler error being from line 1 threw me off, didn't realize that was just a result of the line 9 error below. But could you explain how it is that Foo stops being a function template? Or rather, what is the compiler doing when attempting to process line 9 in both the broken "Foo('a');" and fixed "Foo!(char)('a');" scenarios?
Jul 01 2008
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:g4f8aa$1bkq$1 digitalmars.com...
 I'm still somewhat new to D's templates (been spending a lot of time in 
 non-D development...not by choice), so I'm trying to understand exactly 
 what's going on here as best as I can. Looked up "IFTI" (Implicit Function 
 Template Instantiation), so I see now this method (test2.d) does work, but 
 you have to explicitly instantiate the Foo template when calling the 
 function:

 In main:
 "Foo('a');" -> "Foo!(char)('a');"

 That works. The first compiler error being from line 1 threw me off, 
 didn't realize that was just a result of the line 9 error below.

 But could you explain how it is that Foo stops being a function template? 
 Or rather, what is the compiler doing when attempting to process line 9 in 
 both the broken "Foo('a');" and fixed "Foo!(char)('a');" scenarios?
From what I understand, the compiler considers a template to be a template function if an only if it has exactly one member named the same thing as itself, and that member is a function declaration. Aliases are not function declarations so it fails, though one could argue that an alias is simply a reference _to_ another symbol, so this should work. Of course, none of this is specified. It can't deduce the template function on line 9 simply because it doesn't think that Foo is a template function.
Jul 02 2008
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Jarrett Billingsley" wrote
 "Nick Sabalausky" wrote
 I'm still somewhat new to D's templates (been spending a lot of time in 
 non-D development...not by choice), so I'm trying to understand exactly 
 what's going on here as best as I can. Looked up "IFTI" (Implicit 
 Function Template Instantiation), so I see now this method (test2.d) does 
 work, but you have to explicitly instantiate the Foo template when 
 calling the function:

 In main:
 "Foo('a');" -> "Foo!(char)('a');"

 That works. The first compiler error being from line 1 threw me off, 
 didn't realize that was just a result of the line 9 error below.

 But could you explain how it is that Foo stops being a function template? 
 Or rather, what is the compiler doing when attempting to process line 9 
 in both the broken "Foo('a');" and fixed "Foo!(char)('a');" scenarios?
From what I understand, the compiler considers a template to be a template function if an only if it has exactly one member named the same thing as itself, and that member is a function declaration. Aliases are not function declarations so it fails, though one could argue that an alias is simply a reference _to_ another symbol, so this should work. Of course, none of this is specified. It can't deduce the template function on line 9 simply because it doesn't think that Foo is a template function.
In that case, this should work, but generates extra code (which should be inlined): public void Foo(T: char)(T arg) {Foo_dwc!(T)(arg); } public void Foo(T: wchar)(T arg) {Foo_dwc!(T)(arg); } public void Foo(T: dchar)(T arg) {Foo_dwc!(T)(arg); } private void Foo_dwc(T)(T arg) { } void main(char[][] args) { Foo('a'); } (not tested) -Steve
Jul 02 2008
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Steven Schveighoffer" <schveiguy yahoo.com> wrote in message 
news:g4g2fg$a4l$1 digitalmars.com...

 In that case, this should work, but generates extra code (which should be 
 inlined):

 public void Foo(T: char)(T arg)  {Foo_dwc!(T)(arg); }
 public void Foo(T: wchar)(T arg) {Foo_dwc!(T)(arg); }
 public void Foo(T: dchar)(T arg) {Foo_dwc!(T)(arg); }

 private void Foo_dwc(T)(T arg) {  }

 void main(char[][] args)
 {
 Foo('a');
 }
It does. :)
Jul 02 2008
parent reply "Nick Sabalausky" <a a.a> writes:
"Jarrett Billingsley" <kb3ctd2 yahoo.com> wrote in message 
news:g4g3hd$ckq$1 digitalmars.com...
 "Steven Schveighoffer" <schveiguy yahoo.com> wrote in message 
 news:g4g2fg$a4l$1 digitalmars.com...

 In that case, this should work, but generates extra code (which should be 
 inlined):

 public void Foo(T: char)(T arg)  {Foo_dwc!(T)(arg); }
 public void Foo(T: wchar)(T arg) {Foo_dwc!(T)(arg); }
 public void Foo(T: dchar)(T arg) {Foo_dwc!(T)(arg); }

 private void Foo_dwc(T)(T arg) {  }

 void main(char[][] args)
 {
 Foo('a');
 }
It does. :)
I can't decide if this is better of worse. Leaning towards worse ;) char[] Bar(char[] retType, char[] publicName, char[] privateName, char[] argsDecl, char[] argsCall, char[][] types) { char[] ret; foreach(char[] type; types) { ret ~= "public "~retType~" "~publicName~"(T:"~type~")("~argsDecl~") {"~privateName~"!(T)("~argsCall~");}"; } return ret; } mixin(Bar("void", "Foo", "Foo_dwc", "T arg", "arg", ["char", "wchar", "dchar"])); void main(char[][] args) { Foo('a'); }
Jul 02 2008
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:g4g69h$j7v$1 digitalmars.com...
 I can't decide if this is better of worse. Leaning towards worse ;)

 char[] Bar(char[] retType, char[] publicName, char[] privateName,
                char[] argsDecl, char[] argsCall, char[][] types)
 {
    char[] ret;
    foreach(char[] type; types)
    {
        ret ~= "public "~retType~" "~publicName~"(T:"~type~")("~argsDecl~") 
 {"~privateName~"!(T)("~argsCall~");}";
    }
    return ret;
 }

 mixin(Bar("void", "Foo", "Foo_dwc", "T arg", "arg", ["char", "wchar", 
 "dchar"]));

 void main(char[][] args)
 {
    Foo('a');
 }
Now it's just getting silly. template MakeFunctions(RetType, char[] PublicName, char[] PrivateName, Types...) { static if(Types.length == 0) const char[] MakeFunctions = ""; else const char[] MakeFunctions = "public " ~ RetType.stringof ~ " " ~ PublicName ~ "(T : " ~ Types[0].stringof ~ ")(T arg)\n" "{\n" " return " ~ PrivateName ~ "(arg);\n" "}\n" ~ MakeFunctions!(RetType, PublicName, PrivateName, Types[1 .. $]); } public template NameOfFunc(alias f) { // weirdness in dmdfe. const char[] NameOfFunc = (&f).stringof[2 .. $]; } private template BarImpl(char[] PublicName, alias PrivateFunc, Types...) { alias typeof(&PrivateFunc!(Types[0])) FuncType; alias ReturnTypeOf!(FuncType) RetType; const ret = MakeFunctions!(RetType, PublicName, NameOfFunc!(PrivateFunc!(Types[0])), Types); } public template Bar(char[] PublicName, alias PrivateFunc, Types...) { static assert(Types.length > 0, "must have at least one type"); const Bar = BarImpl!(PublicName, PrivateFunc, Types).ret; } mixin(Bar!("Foo", Foo_dwc, char, wchar, dchar)); Template-foo to the rescue, you can extract the return type directly from the alias to the private function. :)
Jul 02 2008
parent "Nick Sabalausky" <a a.a> writes:
"Jarrett Billingsley" <kb3ctd2 yahoo.com> wrote in message 
news:g4g81l$n9b$1 digitalmars.com...
 "Nick Sabalausky" <a a.a> wrote in message
 news:g4g69h$j7v$1 digitalmars.com...
 I can't decide if this is better of worse. Leaning towards worse ;)

 char[] Bar(char[] retType, char[] publicName, char[] privateName,
                char[] argsDecl, char[] argsCall, char[][] types)
 {
    char[] ret;
    foreach(char[] type; types)
    {
        ret ~= "public "~retType~" 
 "~publicName~"(T:"~type~")("~argsDecl~")
 {"~privateName~"!(T)("~argsCall~");}";
    }
    return ret;
 }

 mixin(Bar("void", "Foo", "Foo_dwc", "T arg", "arg", ["char", "wchar",
 "dchar"]));

 void main(char[][] args)
 {
    Foo('a');
 }
Now it's just getting silly. template MakeFunctions(RetType, char[] PublicName, char[] PrivateName, Types...) { static if(Types.length == 0) const char[] MakeFunctions = ""; else const char[] MakeFunctions = "public " ~ RetType.stringof ~ " " ~ PublicName ~ "(T : " ~ Types[0].stringof ~ ")(T arg)\n" "{\n" " return " ~ PrivateName ~ "(arg);\n" "}\n" ~ MakeFunctions!(RetType, PublicName, PrivateName, Types[1 .. $]); } public template NameOfFunc(alias f) { // weirdness in dmdfe. const char[] NameOfFunc = (&f).stringof[2 .. $]; } private template BarImpl(char[] PublicName, alias PrivateFunc, Types...) { alias typeof(&PrivateFunc!(Types[0])) FuncType; alias ReturnTypeOf!(FuncType) RetType; const ret = MakeFunctions!(RetType, PublicName, NameOfFunc!(PrivateFunc!(Types[0])), Types); } public template Bar(char[] PublicName, alias PrivateFunc, Types...) { static assert(Types.length > 0, "must have at least one type"); const Bar = BarImpl!(PublicName, PrivateFunc, Types).ret; } mixin(Bar!("Foo", Foo_dwc, char, wchar, dchar)); Template-foo to the rescue, you can extract the return type directly from the alias to the private function. :)
I turned that into a working compileable source file (attached, test5.d), and made notes of a few bits of weirdness that I noticed when getting it to compile. I do actually like the end result though. Put it into a utility module, and it's a nicely DRY approach to the original problem that works around D1's lack of template constraints. (I'm a DRY junkie.) I have a few other utility mixins I've been using. When I wrote them, I was having trouble getting template mixins to work without using the "CTFE that returns char[] and takes all-char[] paramaters" approach you saw in my original version of Bar. Studying that code above, I think I understand D's templates well enough now to maybe improve some of those other utility mixins I have. begin 666 test5.d M;6]D=6QE('1E<W0U.PT*#0II;7!O<G0 =&%N9V\N8V]R92Y4<F%I=',[#0II M;7!O<G0 =&%N9V\N:6\N4W1D;W5T.PT*#0IT96UP;&%T92!-86ME1G5N8W1I M;VYS*%)E=%1Y<&4L(&-H87);72!0=6)L:6-.86UE+ T*(" (&-H87);72!0 M<FEV871E3F%M92P 5'EP97,N+BXI#0I[#0H (" <W1A=&EC(&EF*%1Y<&5S M+FQE;F=T:" ]/2 P*0T*(" (" ("!C;VYS="!C:&%R6UT 36%K949U;F-T M:6]N<R ]("(B.PT*(" (&5L<V4-"B (" (" 8V]N<W0 8VAA<EM=($UA M:V5&=6YC=&EO;G, /0T*(" (")P=6)L:6, (B!^(%)E=%1Y<&4N<W1R:6YG M;V8 ?B B("( ?B!0=6)L:6-.86UE('X (BA4(#H (B!^#0H (" (" (%1Y M<&5S6S!=+G-T<FEN9V]F('X (BDH5"!A<F<I7&XB#0H (" (GM<;B(-"B M(" B(" <F5T=7)N("( ?B!0<FEV871E3F%M92!^("(H87)G*3M<;B(-"B M(" B?5QN( T*(" ('X 36%K949U;F-T:6]N<R$H4F5T5'EP92P 4'5B;&EC M3F%M92P 4')I=F%T94YA;64L(%1Y<&5S6S$ +BX )%TI.PT*?0T*#0IP=6)L M:6, =&5M<&QA=&4 3F%M94]F1G5N8RAA;&EA<R!F*0T*>PT*(" ("\O('=E M:7)D;F5S<R!I;B!D;61F92X-"B ("!C;VYS="!C:&%R6UT 3F%M94]F1G5N M8R ](" F9BDN<W1R:6YG;V9;,B N+B D73L-"GT-" T*<')I=F%T92!T96UP M;&%T92!"87));7!L*&-H87);72!0=6)L:6-.86UE+"!A;&EA<R!0<FEV871E M1G5N8RP 5'EP97,N+BXI#0I[#0H)+R\ 4V5E;7, =&\ =V]R:R!W:71H(&5I M=&AE<B B4')I=F%T949U;F,B(&]R("(F4')I=F%T949U;F,B+ T*"2\O(&)U M="!I9B!A;GD ;W1H97( 97)R;W( 97AI<W1S("(F4')I=F%T949U;F,B('=I M;&P 9V5N97)A=&4Z#0H)+R\ =&5S=#4N9" S,BDZ($5R<F]R.B!T=7!L92!I M;F1E>" P(&5X8V5E9', , T*(" (&%L:6%S('1Y<&5O9BA0<FEV871E1G5N M8R$H5'EP97-;,%TI*2!&=6YC5'EP93L-"B ("!A;&EA<R!2971U<FY4>7!E M3V8A*$9U;F-4>7!E*2!29714>7!E.PT*#0H (" 8V]N<W0 <F5T(#T 36%K M949U;F-T:6]N<R$H4F5T5'EP92P 4'5B;&EC3F%M92P-"B (" (" 3F%M M94]F1G5N8R$H4')I=F%T949U;F,A*%1Y<&5S6S!=*2DL(%1Y<&5S*3L-"GT- M" T*<'5B;&EC('1E;7!L871E($)A<BAC:&%R6UT 4'5B;&EC3F%M92P 86QI M87, 4')I=F%T949U;F,L(%1Y<&5S+BXN*0T*>PT*(" ('-T871I8R!A<W-E M<G0H5'EP97,N;&5N9W1H(#X ,"P (FUU<W0 :&%V92!A="!L96%S="!O;F4 M='EP92(I.PT*(" (&-O;G-T($)A<B ]($)A<DEM<&PA*%!U8FQI8TYA;64L M(%!R:79A=&5&=6YC+"!4>7!E<RDN<F5T.PT*?0T*#0HO+R!-:7AI;BA"87(A M*"XN+BDI(&UU<W0 8V]M92!A9G1E<B!T:&ES(&9U;F-T:6]N(&1E8VQA<F%T M:6]N(&]R(&5L<V4Z#0HO+R!T97-T-2YD*#,R*3H =&5M<&QA=&4 :6YS=&%N M8V4 9F]R=V%R9"!R969E<F5N8V4 =&\ =&5M<&QA=&4 9&5C;&%R871I;VX M1F]O7V1W8RA4*0T*<')I=F%T92!V;VED($9O;U]D=V,H5"DH5"!A<F<I('L M4W1D;W5T+F9O<FUA=&QN*")[?2(L(&%R9RD[('T-"FUI>&EN*$)A<B$H(D9O M;R(L($9O;U]D=V,L(&-H87(L('=C:&%R+"!D8VAA<BDI.PT*#0HO+R!497-T M(&5R<F]R(&-O;F1I=&EO; T*+R\ 5&AE('-T871I8R!A<W-E<G0 9&]E<VXG M="!S965M('1O(&=E="!T<FEP<&5D(&EN($1-1" Q+C R.0T*+R\ =&5S=#4N M9" S,BDZ($5R<F]R.B!0<FEV871E1G5N8R$H:6YT*2!I<R!N;W0 86X ;'9A M;'5E#0HO+VUI>&EN*$)A<B$H(D9O;S(B+"!&;V]?9'=C*2D[#0H-"G9O:60 M;6%I;BAC:&%R6UU;72!A<F=S*0T*>PT*"49O;R B8R)C6S!=*3L-" E&;V\H
(G<B=ULP72D[#0H)1F]O*")D(F1;,%TI.PT*?0T*
` end
Jul 02 2008
prev sibling parent reply BCS <ao pathlink.com> writes:
Reply to Jarrett,

 It can't deduce the template function on line 9 simply because it
 doesn't think that Foo is a template function.
 
Should a bug report be filed?
Jul 02 2008
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"BCS" <ao pathlink.com> wrote in message 
news:55391cb32ec1c8caaa3f5f7077a6 news.digitalmars.com...
 Reply to Jarrett,

 It can't deduce the template function on line 9 simply because it
 doesn't think that Foo is a template function.
Should a bug report be filed?
Sure, if you think it'll get any response.
Jul 02 2008
parent BCS <ao pathlink.com> writes:
Reply to Jarrett,

 "BCS" <ao pathlink.com> wrote in message
 news:55391cb32ec1c8caaa3f5f7077a6 news.digitalmars.com...
 
 Reply to Jarrett,
 
 It can't deduce the template function on line 9 simply because it
 doesn't think that Foo is a template function.
 
Should a bug report be filed?
Sure, if you think it'll get any response.
No need to add a new bug. (and Walter seems to like the idea.) http://d.puremagic.com/issues/show_bug.cgi?id=1807
Jul 02 2008