www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Instantiating templates where type is known only at run time

reply "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
this question came up in some C++ work I am doing, but since the
solutions are likely nicer in D, I wanted to ask how it could be
solved in D.

First for some motivation.  I am doing image processing work
where the images are simply an array of data, where the data type
can be any numeric type. The data is stored as binary files and
assume I have some way of figuring out the data type for an image.

Say I want to implement the function along the following lines,
and imagine I have a sane reason for wanting to do such a thing:

//  Assume images are of the same dimensions. Result is
//  saved in Out.
void add(T,U,V)(Image!T A, Image!U B, Image!V Out) {
      ...
}

Now assume I have three variables ImgAType, ImgBType, and
ImgCType (I refer to these variables without specifying their
type, but hopefully it is clear what is going on) then to
implement add() I end up with a lengthy if..else statement or
nasty nested switch ... case statements to handle all the
possible combinations of ubyte, short, uint, float, double for
each of the three image types.  I will use an if() version
example:

if( ImgAType == SHT && ImgBType == UINT && ImgCType == DBL ) {
      Image!short A = new Image!short( filename_of_A );
      Image!uint  B = new Image!uint( filename_of_B );
      Image!double Out = new Image!double( filename_of_Out );
      add(A,B,Out);
} else { //next case and so on .... }

Since the types can be any numeric type there are a lot of
'combinations' of images. I won't add a float and double together
and generate a ubyte image, but there are still many valid
combinations.  However, any way you slice it you end up with a
very long, repetitive bunch of code.

A co-worker of mine came up with (or found) the following
solution. I thought is was clever. It cuts down on repetitive
code, but man is it ugly:

void add( ImgAType, ImgBType, ImgCType, //File names  ) {
     if( ImgAType == UBYTE) AddStep1!ubyte(ImgBType, ImgCType,
//Files );
     else if( ImgAType == SHT) AddStep1!short(ImgBType, ImgCType,
//Files );
     //and so on
}

void AddStep1(T)(ImgBType, ImgCType, //File names ) {
     if( ImgBType == UBYTE) AddStep2!(T,ubyte)(ImgCType, //Files );
     else if( ImgBType == SHT) AddStep2!(T,short)(ImgCType, //Files
);
     //and so on.
}

void AddStep2(T,U)(ImgCType, //File names ) {
     if( ImgCType == UBYTE) AddStep3!(T,U,ubyte)( //Files );
     else if(ImgCType == SHT) AddStep3!(T,U,short)( //Files );
     //and so on
}

void AddStep3(T,U,V)( //File names ) {
     //Do the actual work!
}

Anyway, I hope that is clear what we are trying to do.  So my
question is, is there a nice way in D to instantiate all the
necessary templated functions, and call the correct version at
run time, without resorting one of the methods above.

Anyway, thanks to whoever takes the time to read all that, let
alone come up with an answer.
Nov 19 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Craig Dillabaugh:

 //  Assume images are of the same dimensions. Result is
 //  saved in Out.
 void add(T,U,V)(Image!T A, Image!U B, Image!V Out) {
      ...
 }
Take a look at the "out" annotation in D.
 Anyway, thanks to whoever takes the time to read all that, let
 alone come up with an answer.
In D there is no "type switch" but there are type tuples, where you can put a sequence of all your types, and you can iterate on them statically with a foreach, to instantiate your templates. So your C++ code probably becomes nicer in D. Bye, bearophile
Nov 19 2013
parent "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Tuesday, 19 November 2013 at 12:53:50 UTC, bearophile wrote:
 Craig Dillabaugh:

 //  Assume images are of the same dimensions. Result is
 //  saved in Out.
 void add(T,U,V)(Image!T A, Image!U B, Image!V Out) {
     ...
 }
Take a look at the "out" annotation in D.
 Anyway, thanks to whoever takes the time to read all that, let
 alone come up with an answer.
In D there is no "type switch" but there are type tuples, where you can put a sequence of all your types, and you can iterate on them statically with a foreach, to instantiate your templates. So your C++ code probably becomes nicer in D. Bye, bearophile
Thanks very much. Craig
Nov 19 2013