class template specialization and inheritance

Sean Kelly sean at invisibleduck.org
Tue May 13 18:00:43 PDT 2008


== Quote from mki (none at none.com)'s article
> Hello!
> I just discovered the template syntax of D. I am very exited about its simplicity compared to C++.
> Now I ran into a template behavior I do not understand. This code:
> *** begin code 1 ***
> import std.stdio;
> class A { }
> class B : A { }
> class C(T:A) {
>     static void tellMe() {
>         writefln("derived from A.");
>     }
> }
> class C(T) {
>     static void tellMe() {
>         writefln("generic.");
>     }
> }
> void main() {
>     C!(A).tellMe();
>     C!(B).tellMe();
>     C!(int).tellMe();
> }
> *** end code 1 ***
> as expected produces the output:
> derived from A.
> derived from A.
> generic.
> But this code
> *** begin code 2 ***
> import std.stdio;
> class A(T) { }
> class B(T) : A!(T) { }
> class C(TT:A!(T)) {
>     static void tellMe() {
>         writefln("derived from A!(T).");
>     }
> }
> class C(T) {
>     static void tellMe() {
>         writefln("generic.");
>     }
> }
> void main() {
>     C!(A!(int)).tellMe();
>     C!(B!(int)).tellMe();
>     C!(int).tellMe();
> }
> *** end code 2 ***
> gives the output:
> derived from A!(T).
> generic.
> generic.
> In the second line I would expect the output "derived from A!(T)", like in the example of code 1. My feeling is that
for C!(B!(int))
> 'class C(TT:A!(T))'
> with TT=B!(T) and T=int should be a better specialization than
> 'class C(T)'
> with T=B!(T).
> Why is 'class C(T)' chosen here?

I believe that template expansion like the above requires an exact match for specialization, so
it's basically the same as C++ in this respect.  However, I do think that this is confusing in light
of the "is" syntax where a colon means something different.

> Thanks!
> PS:
> BTW, I thought hard about the question if there is a way to do similar things in C++, that is to have a
specialization of a *class* template which is valid exactly for all classes of a given type A and all classes *derived*
from A. For function templates one can use a SFINAE-trick (the 'enable_if' template in boost) to achieve this, but I
don't see a way to do this for class templates in C++. Does anyone have an idea?

Concept checking can be done in D using the following method:

template isDerivedFromA( T ) {
    const isDerivedFromA = is( T : A );
}
class C( T, bool derivedFromA : false = isDerivedFromA!(T) ) {}
class C( T, bool derivedFromA : true = isDerivedFromA!(T) ) {}

Or if a boolean isn't enough, represent the result using a type:

template getInfoOn( T ) {
    static if( foo ) alias Type1 getInfoOn;
    else static if( bar ) alias Type2 getInfoOn;
    else alias Type3 getInfoOn;
}
class C( T, I : Type1 = getInfoOn!(T) ) {}
class C( T, I : Type2 = getInfoOn!(T) ) {}
class C( T, I : Type3 = getInfoOn!(T) ) {}

I believe a similar approach will work in C++, though you have to be a bit more clever about
implementing the concept checking code.


Sean



More information about the Digitalmars-d mailing list