20

This is what I would like to do:

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();

This doesn't compile because the template type must be specified when declaring the pointer. (ExampleTemplate* pointer_to_template should be ExampleTemplate<int>* pointer_to_template.) Unfortunately, I don't know the type of the template until it's declared in the switch block. What is the best work around for this situation?

Mankarse
  • 39,818
  • 11
  • 97
  • 141
Nathan
  • 5,322
  • 5
  • 24
  • 24
  • 6
    It sounds like you want runtime polymorphism, i.e. virtual functions. Templates are about static polymorphism, i.e. types that are known at compile-time. – Oliver Charlesworth Nov 21 '11 at 00:12

3 Answers3

18

You can't. ExampleTemplate<int> and ExampleTemplate<double> are two different, unrelated types. If you always have a switch over several options, use boost::variant instead.

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

Another way is to use an ordinary base class with virtual public interface, but I'd prefer variant.

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

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

// ..
BaseExample *obj;
Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
  • `boost`? isn't it a little bit complicated for a starter? – juliomalegria Nov 21 '11 at 00:19
  • 4
    let me rephrase: `boost`? it is a little bit complicated for a starter – juliomalegria Nov 21 '11 at 00:21
  • 6
    @julio.alegria: No, it's not. – Cat Plus Plus Nov 21 '11 at 00:25
  • 4
    It entirely depends on the newbie in question. Some people will have little trouble, others would be out of their depth. The OP will decide to follow up on this, or ask questions, or ignore this answer for something he/she understands more readily. But it's good to present "the right way" to do this sort of thing, and to introduce new programmers to good libraries (and get them thinking about such libraries) when approaching software problems. – Mordachai Nov 21 '11 at 00:29
  • 1
    @julio.alegria: In what way? It's just more C++ black boxes. – GManNickG Nov 21 '11 at 03:47
  • 1
    @GMan, I think it isn't a good idea to show C++ as a semi-dynamic typing programming language (at least not for a starter), this could lead to terrible programming mistakes. – juliomalegria Nov 22 '11 at 02:33
10

You can do something similar by having your template class derive from a regular class:

#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;
}
Vlad
  • 18,195
  • 4
  • 41
  • 71
5

What you're trying to do is not possible. This is becase your ExampleTemplate class doesn't exist by itself, only exists when you relate it with a type.

You could get that behaviour using inheritance:

  1. Define a GeneralExampleTemplate (not a template class).
  2. Make ExampleTemplate<T> inherit from GeneralExampleTemplate.
  3. That way you can create a GeneralExampleTemplate pointer and assign it with a (for example) ExampleTemplate<int>.
juliomalegria
  • 24,229
  • 14
  • 73
  • 89