generic toString() in a template class?
Chris Nicholson-Sauls
ibisbasenji at gmail.com
Tue Jan 16 12:36:04 PST 2007
%u wrote:
> I wonder how one could write generic toString() method in a template class?
>
> Suppose, I have a template class S(T), and will pass in as type param: class
> A, struct B, int C:
>
> ====================================
> $ cat ts.d
>
> class A{}
>
> struct B{
> char[] toString() {return "B";}
> }
>
> int c;
>
> class S(T) {
> T obj;
>
> char[] toString() {
> return obj.toString();
> }
>
> }
>
> int main(char[][] args) {
> S!(A) sa;
> S!(B*) sb;
> S!(int) sc;
>
> printf("%.*s", sa.toString());
> printf("%.*s", sb.toString());
> printf("%.*s", sc.toString());
>
> return 0;
> }
>
> $ dmd.exe ts.d
> ts.d(14): Error: no property 'toString' for type 'int'
> ts.d(14): Error: function expected before (), not 1 of type int
> ts.d(14): Error: cannot implicitly convert expression (1()) of type int to char[]
> ts.d(22): template instance ts.S!(int) error instantiating
> ====================================
>
> OK, no property 'toString' for type 'int'; let's use some trick to do function
> overloading:
>
> ====================================
> $ cat ts.d
>
> import std.string;
>
> class A{}
>
> struct B{
> char[] toString() {return "B";}
> }
>
> int c;
>
> char[] toStringFunc(Object obj) {return obj.toString();}
> char[] toStringFunc(int i) {return format(i);}
>
> class S(T) {
> T obj;
>
> char[] toString() {
> return toStringFunc(obj);
> }
>
> }
>
> int main(char[][] args) {
> S!(A) sa;
> S!(B*) sb;
> S!(int) sc;
>
> printf("%.*s", sa.toString());
> printf("%.*s", sb.toString());
> printf("%.*s", sc.toString());
>
> return 0;
> }
>
> $ dmd.exe ts.d
> ts.d(18): function ts.toStringFunc (Object) does not match parameter types (B *)
> ts.d(18): Error: cannot implicitly convert expression (this.obj) of type B *
> to int
> ts.d(25): template instance ts.S!(B *) error instantiating
> ====================================
>
> OK, struct is not Object, so let's just add char[] toStringFunc(void* obj)
> {return "null";}
>
> ====================================
> $ cat ts.d
> import std.string;
>
> class A{}
>
> struct B{
> char[] toString() {return "B";}
> }
>
> int c;
>
> char[] toStringFunc(Object obj) {return obj.toString();}
> char[] toStringFunc(int i) {return format(i);}
> char[] toStringFunc(void* obj) {return "null";}
>
> class S(T) {
> T obj;
>
> char[] toString() {
> return toStringFunc(obj);
> }
>
> }
>
> int main(char[][] args) {
> S!(A) sa;
> S!(B*) sb;
> S!(int) sc;
>
> printf("%.*s", sa.toString());
> printf("%.*s", sb.toString());
> printf("%.*s", sc.toString());
>
> return 0;
> }
>
> $ dmd.exe ts.d
> ts.d(19): function ts.toStringFunc called with argument types:
> (A)
> matches both:
> ts.toStringFunc(Object)
> and:
> ts.toStringFunc(void*)
> ts.d(25): template instance ts.S!(A) error instantiating
> ====================================
>
> Come on! class A matches both (Object) and (void*)?!
>
> How could one write a generic toString() method in a template class then?
>
> My suggestions:
>
> -- if the compiler see a basic type, int.toString(), translate into a function
> that does the Right Thing; just as if .toString() is also a property of basic
> types like int.max, int.min.
>
> -- class A, matches (Object) better than (void*), so just do the Right thing
> to choose overloaded-function(Object obj).
>
>
> comments?
Current D, off the top of my head:
# class S (T) {
# T obj ;
#
# char[] toString () {
# static if (is(T == class)) {
# return obj.toString;
# }
# else static if (is(T == struct)) {
# static if (is(typeof(T.toString() == char[])))
# return obj.toString;
# }
# else {
# static assert (false, "class S!(T): struct T must expose function char[]
toString()");
# }
# }
# else {
# std.string.toString(obj);
# }
# }
# }
-- Chris Nicholson-Sauls
More information about the Digitalmars-d
mailing list