Как я могу объявить указатель шаблона, не зная типа? - PullRequest
18 голосов
/ 21 ноября 2011

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

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.) К сожалению, я не знаю тип шаблона, пока он не объявлен в блоке переключателя. Как лучше обойти эту ситуацию?

Ответы [ 3 ]

17 голосов
/ 21 ноября 2011

Вы не можете. 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;
6 голосов
/ 21 ноября 2011

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

#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;
}
5 голосов
/ 21 ноября 2011

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

Такое поведение можно получить с помощью наследования:

  1. ОпределитеGeneralExampleTemplate (не шаблонный класс).
  2. Сделать ExampleTemplate<T> наследуемым от GeneralExampleTemplate.
  3. Таким образом, вы можете создать указатель GeneralExampleTemplate и назначить его с помощью (например,) ExampleTemplate<int>.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...