Условно создать шаблон во время выполнения - PullRequest
4 голосов
/ 27 ноября 2009

У меня есть шаблон класса


template <class T> 
class myClass
{
    public:
        /* functions */
    private:
        typename T::Indices myIndices;  
};
 

Теперь в моем основном коде я хочу создать экземпляр класса шаблона в зависимости от условия. Нравится:


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

Теперь проблема этого подхода заключается в том, что auto_ptr<> умрет в конце switch{}. И я не могу объявить это в начале функции, потому что я не знаю тип, который будет создан ранее.

Я знаю, что пытаюсь добиться выполнения во время компиляции (используя шаблон), но все же хотел знать, есть ли какой-нибудь лучший способ сделать это.

Ответы [ 5 ]

7 голосов
/ 27 ноября 2009

Создать базовый класс

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..
}
4 голосов
/ 27 ноября 2009

Вы можете ввести общую базу для myClass и использовать ее в качестве параметра для auto_ptr. Только не забудьте объявить деструктор этой общей базы виртуальным.

2 голосов
/ 27 ноября 2009

Boost.Variant должен добиться цели.

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

Использование объекта немного отличается, потому что тип определяется динамически. Техника apply_visitor - определенно путь; см. учебник о том, как его использовать.

1 голос
/ 27 ноября 2009

Вы можете добавить уровень косвенности, чтобы получить то, что вы хотите. Вы можете избежать базового класса с помощью виртуальных методов и делать любые другие специальные вещи.

Например:

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>();
        // ...
     }
 }
0 голосов
/ 27 ноября 2009

низкотехнологичное решение. используйте обычный указатель с желаемой областью действия.

...