Reputation: 21
I'm trying to find an efficient way to invoke a specific C++ template type based dynamic value of a variable. Currently I'm not clear on how to approach this, except by using large and ugly if/else selector for a large set of permutations as in the example below. As you can see this is not pretty.
Instead I'd like to invoke suitable template dynamically without huge if/else selector...
Any advise from the C++ template masters out there would be much appreciated.
// crude generic data converter template invoked based on dynamic in/out buffer type
template <class dstType, class srcType>
void ConvertCopy(unsigned char* dst, const unsigned char* src, int size)
{
// requires same in/out buffer same dimensions
if (typeid(srcType) != typeid(dstType))
{
dstType* c_dst = (dstType*)dst;
srcType* c_src = (srcType*)src;
for(int i=0;i<size;i++)
c_dst[i] = (dstType)c_src[i];
}
else
memcpy(dst, src, size * sizeof(srcType)); // Plain copy
}
void test()
{
const int buffersize = 100;
int inbuffer[buffersize];
double outbuffer[buffersize];
unsigned char* anyIn = (unsigned char*)inbuffer;
unsigned char* anyOut = (unsigned char*)outbuffer;
int my_in_type = 1;
int my_out_type = 3;
if(my_in_type == 1) { // int
if(my_out_type == 1) ConvertCopy<int, int>(anyOut, anyIn, buffersize); // int -> int
if(my_out_type == 2) ConvertCopy<float, int>(anyOut, anyIn, buffersize); // int -> float
if(my_out_type == 3) ConvertCopy<double, int>(anyOut, anyIn, buffersize); // int -> double
// ...
}
else if(my_in_type == 2) { // unsigned int
if(my_out_type == 1) ConvertCopy<int, unsigned int>(anyOut, anyIn, buffersize); // unsigned int -> int
if(my_out_type == 2) ConvertCopy<float, unsigned int>(anyOut, anyIn, buffersize); // unsignedint -> float
if(my_out_type == 3) ConvertCopy<double, unsigned int>(anyOut, anyIn, buffersize); // unsigned int -> double
// ...
}
else {}
// ...
}
Upvotes: 1
Views: 277
Reputation: 664
MSVC compiles down to it's .NET
code (oversimplification), which allows you to use elements from other Microsoft languages. In Visual C++, there is a keyword known as 'generic` and it works like a template but may allow for what you're wanting.
Microsoft has a few pages of documentation on this, but here is the link to the overview page.
Upvotes: 0
Reputation: 40043
There’s no way (short of the very young JIT proposals) to avoid a branch or lookup table: it is a feature that different specializations of a function template can have unrelated types (with some restrictions on the parameter types, especially when supporting deduction), making it implausible to support a call with a dynamic template argument in the type system even if it were known to be drawn from a small set. (Yours all happen to be void(unsigned char*,const unsigned char*,int)
, but for consistency the rules do not consider that.)
That said, the boilerplate can be expressed efficiently in cases like this where the type doesn’t vary:
template<class D>
auto copier(int s) {
switch(s) {
case 1: return ConvertCopy<D,int>;
case 2: return ConvertCopy<D,unsigned>;
// …
}
}
void test() {
// …
[](int d) {
switch(d) {
case 1: return copier<int>;
case 2: return copier<float>;
case 3: return copier<double>;
// …
}
}(my_out_type)(my_in_type)(anyOut,anyIn,buffersize);
}
This approach reduces the verbosity to O(m+n) from O(mn). It may help if you think of the extra sets of parentheses as being separate because they are like “runtime template argument lists”.
It would of course be possible to generalize this to produce a value of any consistent type from a metafunction with (for practicality) a known range of interesting inputs.
Upvotes: 3