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

Craig

In 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;
}

Reply via email to