Thread overview
generalising template specialisation
Nov 11, 2006
Thomas Kuehne
Nov 11, 2006
Sean Kelly
Nov 12, 2006
Bill Baxter
Nov 12, 2006
Sean Kelly
Nov 12, 2006
Kristian Kilpi
November 11, 2006
I am going to use TemplateTypeParameterSpecialization in the samples below, all the ideas apply to TemplateValueParameterSpecialization too.


Current specialisation:
#
# template A (T : SomeType) { /* ... */ }
#

Template A matches if T is implicitly convertible to SomeType.


How do you define a template that matches if T is a struct?
#
# template B (T) {
#    static if(is(T == struct)) {
#	/* ... */
#    } else {
#       static assert(0, "use a struct");
#    }
# }
#

OK that works, though the error will be reported on the assert line instead of the instantiation line. Now suppose someoneelse writes a template with the same functionality that supports classes:

#
# template B (T) {
#    static if(is(T == class)) {
#	/* ... */
#    } else {
#       static assert(0, "use a class");
#    }
# }
#

Err, won't work:
b2.d(1): template b2.B(T) conflicts with b1.B(T) at b1.d(1)

Solution 1: merge those templates
#
# template B (T) {
#    static if(is(T == class)) {
#	/* ... */
#    } else if(is(T == struct)) {
#	/* ... */
#    } else {
#       static assert(0, "use a class or struct");
#    }
# }
#

Problem: Merging 2 templates having different licenses and maintainers can become a nightmare.

Solution 2: use a meta template
#
# private import b1, b2;
#
# template B (T) {
#    static if(is(T == class)) {
#	alias b1.B!(T) B;
#    } else if(is(T == struct)) {
#	alias b2.B!(T) B;
#    } else {
#       static assert(0, "use a class or struct");
#    }
# }
#

Problem: This is a very brittle approach introducing an extra level of indirection and will fail if someone writes a third template supporting e.g. delegates.

Please lift the current limitation and support all constructs allowed by StaticIfCondition in TemplateTypeParameterSpecialization too.

Rewriting the B templates:
#
# template B( T : is(T == class)) {
#    /* ... */
# }
#
# template B( T : is(T == struct)) {
#    /* ... */
# }
#

I'm not aware of any lexicographic issues or problems with existing code.

Thomas


November 11, 2006
Thomas Kuehne wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> I am going to use TemplateTypeParameterSpecialization in the samples
> below, all the ideas apply to TemplateValueParameterSpecialization too.
> 
> 
> Current specialisation:
> #
> # template A (T : SomeType) { /* ... */ }
> #
> 
> Template A matches if T is implicitly convertible to SomeType.
> 
> 
> How do you define a template that matches if T is a struct?
> #
> # template B (T) {
> #    static if(is(T == struct)) {
> #	/* ... */
> #    } else {
> #       static assert(0, "use a struct");
> #    }
> # }
> # 
> 
> OK that works, though the error will be reported on the assert line
> instead of the instantiation line.

This is where concept checking is really useful.  However, you can overload on concepts in D using something like the following:

struct ClassType {}
struct StructType {}
...

template TypeOf( T ) {
    static if( is( T == class ) )
        alias ClassType TypeOf;
    else static if( is( T == struct ) )
        alias StructType TypeOf;
    ...
}

template ClassTempl( T, Type : ClassType = TypeOf!(T) ) {
    // make sure the user didn't cheat
    static assert( is( Type == TypeOf!(T) );
    ...
}

template StructTempl( T Type : StructType = TypeOf!(T) ) {
    // make sure the user didn't cheat
    static assert( is( Type == TypeOf!(T) );
    ...
}

It's a bit messy, but it works.


Sean
November 12, 2006
Thomas Kuehne wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> I am going to use TemplateTypeParameterSpecialization in the samples
> below, all the ideas apply to TemplateValueParameterSpecialization too.
> 
> 
> Current specialisation:
> #
> # template A (T : SomeType) { /* ... */ }
> #
> 
> Template A matches if T is implicitly convertible to SomeType.
> 
> 
> How do you define a template that matches if T is a struct?
> #
> # template B (T) {
> #    static if(is(T == struct)) {
> #	/* ... */
> #    } else {
> #       static assert(0, "use a struct");
> #    }
> # }
> # 
> 
> OK that works, though the error will be reported on the assert line
> instead of the instantiation line. Now suppose someoneelse writes a
> template with the same functionality that supports classes:
> 
> #
> # template B (T) {
> #    static if(is(T == class)) {
> #	/* ... */
> #    } else {
> #       static assert(0, "use a class");
> #    }
> # }
> # 
> 
> Err, won't work:
> b2.d(1): template b2.B(T) conflicts with b1.B(T) at b1.d(1)
> 
> Solution 1: merge those templates
> #
> # template B (T) {
> #    static if(is(T == class)) {
> #	/* ... */
> #    } else if(is(T == struct)) {
> #	/* ... */
> #    } else {
> #       static assert(0, "use a class or struct");
> #    }
> # }
> # 
> 
> Problem: Merging 2 templates having different licenses and maintainers
> can become a nightmare.
> 
> Solution 2: use a meta template
> #
> # private import b1, b2;
> #
> # template B (T) {
> #    static if(is(T == class)) {
> #	alias b1.B!(T) B;
> #    } else if(is(T == struct)) {
> #	alias b2.B!(T) B;
> #    } else {
> #       static assert(0, "use a class or struct");
> #    }
> # }
> #
> 
> Problem: This is a very brittle approach introducing an extra level
> of indirection and will fail if someone writes a third template
> supporting e.g. delegates.
> 
> Please lift the current limitation and support all constructs allowed by
> StaticIfCondition in TemplateTypeParameterSpecialization too.
> 
> Rewriting the B templates:
> #
> # template B( T : is(T == class)) {
> #    /* ... */
> # }
> #
> # template B( T : is(T == struct)) {
> #    /* ... */
> # }
> #
> 
> I'm not aware of any lexicographic issues or problems with existing
> code.
> 
> Thomas

+1.

Don't have much to add, but I agree that for serious libraries, 3rd party code needs to be able to add new specializations without modifying the source of the original.

--bb
November 12, 2006
Thomas Kuehne wrote:
> 
> Please lift the current limitation and support all constructs allowed by
> StaticIfCondition in TemplateTypeParameterSpecialization too.
> 
> Rewriting the B templates:
> #
> # template B( T : is(T == class)) {
> #    /* ... */
> # }
> #
> # template B( T : is(T == struct)) {
> #    /* ... */
> # }
> #

By the way, in case it didn't seem like it in my other post, I would *love* to have a feature like this.  It would be a reasonable substitute for concept checking in D.


Sean
November 12, 2006
On Sat, 11 Nov 2006 18:31:02 +0200, Thomas Kuehne <thomas-dloop@kuehne.cn> wrote:
> Please lift the current limitation and support all constructs allowed by
> StaticIfCondition in TemplateTypeParameterSpecialization too.
>
> Rewriting the B templates:
> #
> # template B( T : is(T == class)) {
> #    /* ... */
> # }
> #
> # template B( T : is(T == struct)) {
> #    /* ... */
> # }
> #

I fully agree.