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