class template specialization and inheritance

mki none at none.com
Tue May 13 23:52:03 PDT 2008


Sean Kelly Wrote:

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

In the article
http://www.digitalmars.com/d/2.0/templates-revisited.html
I found the example

class Foo(
  R,            // R can be any type
  P:P*,         // P must be a pointer type
  T:int,        // T must be int type
  S:T*,         // S must be pointer to T
  C:B,          // C must be of class B or derived
                // from B
  U:I,          // U must be a class that
                // implements interface I
  string str = "hello",
                // string literal,
                // default is "hello"
  alias A = B   // A is any symbol
                // (including template symbols),
                // defaulting to B
  )

So according to the comment in the 6th line the colon includes inherited classes.
Also, in my example "code 1" the colon works this way:
Since the second line of the output is
"derived from A."
C!(B) matches the expression C(T:A) with T=B

It seems that the additional template parameter T of class A somehow makes a difference in "code 2". But I still don't see why this should be.

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

Up to here this can also be done in C++, for the getInfoOn template there should be some substitute in the boost library.

But my problem ist that I need to end up with a class template C(T) depending only on *one* template parameter, the class T (which might depend on a template parameter itself).
Currently I have this problem in a programming project in C++, and I did not find a solution. I consider switching to D, but at the moment I don't see a solution in D, either.



More information about the Digitalmars-d mailing list