Подтвердить что ты не робот

Как я могу объявить указатель шаблона, не зная тип?

Это то, что я хотел бы сделать:

ExampleTemplate* pointer_to_template;
cin >> number;
switch (number) {
case 1:
    pointer_to_template = new ExampleTemplate<int>();
    break;
case 2:
    pointer_to_template = new ExampleTemplate<double>();
    break;
}
pointer_to_template->doStuff();

Это не скомпилируется, потому что тип шаблона должен быть указан при объявлении указателя. (ExampleTemplate* pointer_to_template должно быть ExampleTemplate<int>* pointer_to_template.) К сожалению, я не знаю тип шаблона, пока он не будет объявлен в блоке коммутатора. Какая самая лучшая работа для этой ситуации?

4b9b3361

Ответ 1

Вы не можете. ExampleTemplate<int> и ExampleTemplate<double> - два разных, не связанных между собой типа. Если у вас всегда есть переключатель по нескольким параметрам, используйте boost::variant вместо этого.

typedef boost::variant<Example<int>, Example<double>> ExampleVariant;
ExampleVariant v;
switch (number) {
    case 1: v = Example<int>(); break;
    case 2: v = Example<double>(); break;
}
// here you need a visitor, see Boost.Variant docs for an example

Другой способ - использовать обычный базовый класс с виртуальным открытым интерфейсом, но я бы предпочел variant.

struct BaseExample {
    virtual void do_stuff() = 0;
    virtual ~BaseExample() {}
};

template <typename T>
struct Example : BaseExample { ... };

// ..
BaseExample *obj;

Ответ 2

Вы можете сделать что-то подобное, если ваш шаблонный класс получен из обычного класса:

#include<iostream>
#include<sstream>
using namespace std;

class ExampleBase{

public:
    virtual ~ExampleBase() {}
    virtual string Get() = 0;
};

template<typename T>
class ExampleTemplate : public ExampleBase{

private:
    T data;

public:
    ExampleTemplate(T t) : data(t){}

    string Get(){        
        stringstream s; s << data;
        return s.str();
    }

};

int main(){

    ExampleBase *base;
    int number;
    cout << "> " << flush; cin >> number;

    switch(number){
        case 1:
            base = new ExampleTemplate<int>(42);
            break;
        case 2:
            base = new ExampleTemplate<double>(3.14);
            break;
        default:
            return 1;
    }

    cout << base->Get() << endl;

    delete base;
    return 0;
}

Ответ 3

То, что вы пытаетесь сделать, невозможно. Это потому, что ваш класс ExampleTemplate не существует сам по себе, существует только тогда, когда вы связываете его с типом.

Вы можете получить это поведение, используя наследование:

  • Определите GeneralExampleTemplate (а не шаблонный класс).
  • Сделать ExampleTemplate<T> наследовать от GeneralExampleTemplate.
  • Таким образом вы можете создать указатель GeneralExampleTemplate и назначить его (например) ExampleTemplate<int>.