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.
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.
 



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