Conditionally instantiate a template at run-time
-
05-07-2019 - |
Question
I have a template class
template <class T>
class myClass
{
public:
/* functions */
private:
typename T::Indices myIndices;
};
Now in my main code I want to instantiate the template class depending on a condition. Like :
myFunc( int operation)
{
switch (operation) {
case 0:
// Instantiate myClass with <A>
auto_ptr < myClass <A> > ptr = new myClass<A> ();
case 1:
// Instantiate myClass with <B>
auto_ptr < myClass <B> > ptr = new myClass<B> ();
case 2:
// Instantiate myClass with <C>
....
}
// Use ptr here..
}
Now the problem with this approach is that the auto_ptr<>
will die at the end of switch{}
.
And I can't declare it at the beginning of the function, because I don't know the type that will be instantiated before-hand.
I know I'm trying to achieve a run-time thing at compile-time (using template), but still wanted to know if there is some better way to do this.
Solution
Create a base class
class Base {
protected:
virtual ~Base() {}
//... functions
};
template <class T> class myClass : Base {
//...
};
myFunc( int operation){
shared_ptr < Base > ptr;
switch (operation) {
case 0:
// Instantiate myClass with <A>
ptr.reset ( new myClass<A> () );
case 1:
// Instantiate myClass with <B>
ptr.reset ( new myClass<B> () ) ;
case 2:
// Instantiate myClass with <C> ....
}
// Use ptr here..
}
OTHER TIPS
You could introduce a common base to myClass
and use that as the parameter to auto_ptr
. Just don't forget to declare that common base's destructor virtual.
Boost.Variant should do the trick.
myFunc( int operation)
{
boost::variant< myclass<A>, myclass<B> > obj;
switch (operation) {
case 0:
// Instantiate myClass with <A>
obj = myClass<A> ();
case 1:
// Instantiate myClass with <B>
obj = myClass<B> ();
case 2:
// Instantiate myClass with <C>
....
}
// Use object here..
}
Using the object is a little different because the type is dynamically determined. The apply_visitor technique is definitely the way to go; see the tutorial for how to use it.
You can add a level of indirection to get what you want. You can avoid a base class with virtual methods and doing any other special stuff.
For example:
template <class T>
class MyClass
{
public:
/* functions */
private:
typename T::Indices myIndices;
};
template<typename T>
static void doit()
{
MyClass<T> t;
// Use t here.
}
void myfunc(int op)
{
switch (op) {
case 0: return doit<A>();
case 1: return doit<B>();
// ...
}
}
low tech solution. use a regular pointer with the scope you want.