digitalmars.D.learn - A good advertisement for 'static if'
- Craig Dillabaugh (57/57) Dec 12 2013 I am not sure if this belongs in D.learn, but it might be of
- FreeSlave (33/93) Dec 12 2013 In C++ you can use partial specialization to achieve what you
- FreeSlave (3/3) Dec 12 2013 With some improvements you also can provide compile-time error
- Craig Dillabaugh (14/61) Dec 12 2013 Thanks for this suggestion, it avoids the reinterpret cast
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 > RAWImageDataStore<T>* getBandData( ) { T t; //Check struct data type vs template type. if( datatype == TYPE_8u && typeid(t) == typeid(uint8_t) ) { return reinterpret_cast< RAWImageDataStore<T>* >( data.t8u ); } else if ( datatype == TYPE_16s && typeid(t) == typeid(int16_t) ) { return reinterpret_cast< RAWImageDataStore<T>* >( 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::complex<int16_t>) ) { return reinterpret_cast< RAWImageDataStore<T>* >( 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 RAWImageDataStore<int8_t>*, but have to cast it to RAWImageDataStore<int8_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
Dec 12 2013
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 > RAWImageDataStore<T>* getBandData( ) { T t; //Check struct data type vs template type. if( datatype == TYPE_8u && typeid(t) == typeid(uint8_t) ) { return reinterpret_cast< RAWImageDataStore<T>* >( data.t8u ); } else if ( datatype == TYPE_16s && typeid(t) == typeid(int16_t) ) { return reinterpret_cast< RAWImageDataStore<T>* >( 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::complex<int16_t>) ) { return reinterpret_cast< RAWImageDataStore<T>* >( 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 RAWImageDataStore<int8_t>*, but have to cast it to RAWImageDataStore<int8_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'. CraigIn C++ you can use partial specialization to achieve what you want. class Storage { public: union { float* fdata; int* idata; } data; }; template<typename T> T* get(Storage& stor) { return 0; //or throw exception } template<> float* get<float>(Storage& stor) { return stor.data.fdata; } template<> int* get<int>(Storage& stor) { return stor.data.idata; } int main() { Storage stor; float* fdata = get<float>(stor); return 0; }
Dec 12 2013
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++.
Dec 12 2013
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:clipI 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).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, CraigMaybe 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'. CraigIn C++ you can use partial specialization to achieve what you want. class Storage { public: union { float* fdata; int* idata; } data; }; template<typename T> T* get(Storage& stor) { return 0; //or throw exception } template<> float* get<float>(Storage& stor) { return stor.data.fdata; } template<> int* get<int>(Storage& stor) { return stor.data.idata; } int main() { Storage stor; float* fdata = get<float>(stor); return 0; }
Dec 12 2013