A good advertisement for 'static if'
I am not sure if this belongs in D.learn, but it might be of interest. I was writing some C++ code for a project at work and have a class that stores image data from a file. The image data can be in just about any numeric (int/float/complex) type, so I wanted a 'wrapper' class/struct that could hold any type of data without being 'parameterized' (we use templates for image access). My class contains a union ( called 'data') with every possible type of pointer and parameter for indicating the data type. However, at some point code eventually needs to get at the data, so I have the following beauty of a template method, (calling the image structure RAWImageDataStore was a bad design decision on my part, need to change that soon, its very Java-esque): template class T RAWImageDataStoreT* getBandData( ) { T t; //Check struct data type vs template type. if( datatype == TYPE_8u typeid(t) == typeid(uint8_t) ) { return reinterpret_cast RAWImageDataStoreT* ( data.t8u ); } else if ( datatype == TYPE_16s typeid(t) == typeid(int16_t) ) { return reinterpret_cast RAWImageDataStoreT* ( data.t16s ); } //a number of types left out, I am sure you get the idea. //but you need to see the complex types, they are beautiful. else if ( datatype == TYPE_C16s typeid(t) == typeid(std::complexint16_t) ) { return reinterpret_cast RAWImageDataStoreT* ( data.tC16s ); } \\OK, you only really needed to see one of the complex types :o) else if( datatype == TYPE_UNKNOWN ) { std::cerr Cannot access band with unknown data type. std::endl; return 0; } //+ a bit more error handling code. Initially this didn't compile because I was missing the reinterpret_cast statements. They effectively do nothing. If the template type is int8_t then I return the data.t8u pointer, which is a RAWImageDataStoreint8_t*, but have to cast it to RAWImageDataStoreint8_t*. I must do this because when I call the method type int16_t my return data.t8u returns the wrong type of pointer for the method, even though I know that if the type is int16_t this statement can never be reached. I know there was some debate in the C++ community about whether they should adopt D-like static if, which would have solved this problem, since it would compile the illegal code right out of existence. Maybe there is a better way to do this in C++, but I thought I would post here as a case-study in the usefulness of 'static if'. Craig
Re: A good advertisement for 'static if'
On Thursday, 12 December 2013 at 14:55:28 UTC, Craig Dillabaugh wrote: I am not sure if this belongs in D.learn, but it might be of interest. I was writing some C++ code for a project at work and have a class that stores image data from a file. The image data can be in just about any numeric (int/float/complex) type, so I wanted a 'wrapper' class/struct that could hold any type of data without being 'parameterized' (we use templates for image access). My class contains a union ( called 'data') with every possible type of pointer and parameter for indicating the data type. However, at some point code eventually needs to get at the data, so I have the following beauty of a template method, (calling the image structure RAWImageDataStore was a bad design decision on my part, need to change that soon, its very Java-esque): template class T RAWImageDataStoreT* getBandData( ) { T t; //Check struct data type vs template type. if( datatype == TYPE_8u typeid(t) == typeid(uint8_t) ) { return reinterpret_cast RAWImageDataStoreT* ( data.t8u ); } else if ( datatype == TYPE_16s typeid(t) == typeid(int16_t) ) { return reinterpret_cast RAWImageDataStoreT* ( data.t16s ); } //a number of types left out, I am sure you get the idea. //but you need to see the complex types, they are beautiful. else if ( datatype == TYPE_C16s typeid(t) == typeid(std::complexint16_t) ) { return reinterpret_cast RAWImageDataStoreT* ( data.tC16s ); } \\OK, you only really needed to see one of the complex types :o) else if( datatype == TYPE_UNKNOWN ) { std::cerr Cannot access band with unknown data type. std::endl; return 0; } //+ a bit more error handling code. Initially this didn't compile because I was missing the reinterpret_cast statements. They effectively do nothing. If the template type is int8_t then I return the data.t8u pointer, which is a RAWImageDataStoreint8_t*, but have to cast it to RAWImageDataStoreint8_t*. I must do this because when I call the method type int16_t my return data.t8u returns the wrong type of pointer for the method, even though I know that if the type is int16_t this statement can never be reached. I know there was some debate in the C++ community about whether they should adopt D-like static if, which would have solved this problem, since it would compile the illegal code right out of existence. Maybe there is a better way to do this in C++, but I thought I would post here as a case-study in the usefulness of 'static if'. Craig In C++ you can use partial specialization to achieve what you want. class Storage { public: union { float* fdata; int* idata; } data; }; templatetypename T T* get(Storage stor) { return 0; //or throw exception } template float* getfloat(Storage stor) { return stor.data.fdata; } template int* getint(Storage stor) { return stor.data.idata; } int main() { Storage stor; float* fdata = getfloat(stor); return 0; }
Re: A good advertisement for 'static if'
With some improvements you also can provide compile-time error about instantiation of non-specialized function (i.e. which has T as parameter), but I'm not sure what's good way to do it in C++.
Re: A good advertisement for 'static if'
On Thursday, 12 December 2013 at 17:34:13 UTC, FreeSlave wrote: On Thursday, 12 December 2013 at 14:55:28 UTC, Craig Dillabaugh wrote: I am not sure if this belongs in D.learn, but it might be of interest. I was writing some C++ code for a project at work and have a class that stores image data from a file. The image data can be in just about any numeric (int/float/complex) type, so I wanted a 'wrapper' class/struct that could hold any type of data without being 'parameterized' (we use templates for image access). clip Maybe there is a better way to do this in C++, but I thought I would post here as a case-study in the usefulness of 'static if'. Craig In C++ you can use partial specialization to achieve what you want. class Storage { public: union { float* fdata; int* idata; } data; }; templatetypename T T* get(Storage stor) { return 0; //or throw exception } template float* getfloat(Storage stor) { return stor.data.fdata; } template int* getint(Storage stor) { return stor.data.idata; } int main() { Storage stor; float* fdata = getfloat(stor); return 0; } Thanks for this suggestion, it avoids the reinterpret cast nicely. I've used template specialization in other cases, but it didn't occur to me in this case (plus adding the 'reinterpret_cast' required less refactoring on my part at the time). However, I may switch my code to use this method since the resulting executable should be smaller/faster since the big if ... else statement isn't inserted with every template instantiation. However neither solution is as nice as 'static if' in D. The benefits of having all my type checks in one space, and the 'dead' code is eliminated in the instantiations. Cheers, Craig