I am creating an algorithm that deals with many different user defined types at once. Each of these types will be assumed to have a func1
and func2
that will be the interface for MyAlgorithm
. I can do this using variadic templates:
template <typename... Args>
class MyAlgorithm{
// interact with Args using func1 and func2
};
I can now instantiate MyAlgorithm
like so MyAlgorithm<A, B, C, D, E, F, G>
. This works, however, I feel as though for my application this may result in too many specializations of MyAlgorithm
. In practice, MyAlgorithm
may be instantiated first like MyAlgorithm<A, B, B , A, C, D>
, then MyAlgorithm<A, A, C, D>
, and then MyAlgorithm<C, F D>
, and so on.
Unfortunately, the template is instantiated for every combination of Args
. This creates problems, for example, in the online setting. MyAlgorithm
may be run on batches of live input data (the nature of MyAlgorithm
is that it runs on batches rather than individual inputs). The live input data will be parsed and the correct specialization of MyAlgorithm
will be called. In this case, the user will need to create all possible specializations of MyAlgorithm
in the compiled code.
MyAlgorithm<A>;
MyAlgorithm<B>;
MyAlgorithm<C>;
MyAlgorithm<A, A>;
MyAlgorithm<A, B>;
MyAlgorithm<A, C>;
MyAlgorithm<B, A>;
...
I had an idea that may be able to help, but I haven't gotten it exactly right. Instead of MyAlgorithm
taking template parameters, it will deal with a template Proxy
class that is specialized to the A, B, Cs
.
// no template
class MyAlgorithm{
// interact with Proxy using func1proxy and func2proxy
std::vector<Proxy> Args;
};
template<typename T>
class Proxy{
// define func1proxy and func2proxy using Arg's func1 and func2
std::unique_ptr<T> Arg; // only member
};
Of course this doesn't work because each Proxy
specialization is a different class and so MyAlgorithm
still needs to be a template class (and std::vector<Proxy> Args
can't exist).
Is there a design pattern for what I want to do? Is there a design pattern that reduces the number of class instantiations?
Some notes:
MyAlgorithm
treats all template arguments the same. The algorithm recursively calls func1
and func2
on each template argument.
class MyAlgorithm{
template<typname T, typename... Args>
void CallFunc1s(T first, Args... rest){
T.func1();
SomeFunction(rest);
}
};
Type erase a type T to be called by func1/func2.
struct proxy_ref{
void* pdata=0;
void(*pfunc1)(void*)=0;
void(*pfunc2)(void*)=0;
template<class T>
proxy_ref(T&& t):
pdata((void*)std::addressof(t)),
pfunc1([](void*pvoid){
((T*)pvoid)->func1();
}),
pfunc2([](void*pvoid){
((T*)pvoid)->func2();
})
{}
void func1(){ pfunc1(pvoid); }
void func2(){ pfunc2(pvoid); }
};
now take a vector of proxy_ref
s and call func1
and func2
on them.
Your particular problem could involve more complex signatures, or even value types instead of ref types.
There are problems like yours that type erasure cannot solve, but trying this is a first step.