Reputation: 25
I wrote different function objects A, B, and C in C++ and I want to instantiate a template class with one of the function objects, depending on the user input. But as it seems there is no way to instantiate only one of the types in an if statement, is it?
If I try to instantiate one class with a template in the if statement, the g++ compiler gives me a "use of undeclared identifier 'bkt'"-error. If I instantiate it beforehand, the class destroys itself when leaving the if-statement.
Here's my code:
class A {
public: void operator()(int a) {}
};
class B {
public: void operator()(int a) {}
};
class C {
public: void operator()(int a) {}
};
template <typename T>
class MyClass {
public:
MyClass<T>(const std::string &file);
~MyClass<T>;
private:
T m_func;
int doStuff(int a) {
return m_func(a);
}
};
int main() {
std::string filename = std::string(argv[1]);
std::getline(std::cin, metric);
if (metric == "A") {
MyClass<A> foo(filename);
}
else if (metric == "B") {
MyClass<B> foo(filename);
}
else {
MyClass<C> foo(filename);
}
int a = 1;
foo.doStuff(int a); // undeclared identifier "foo"
getchar();
return 0;
}
I know, that I somehow have to declare the foo-variable, but I was hoping the compiler might be ok with it because one of the cases of the if-statement will happen anyways. Obviously it's not, so what can I do in order to not instantiate every single type?
Upvotes: 0
Views: 1183
Reputation: 122133
In simple terms: Templates help you with compile-time polymorphism but what you want is runtime-polymorphism. However, it is straightforward to mix them.
First you create a base class:
struct MyBase {
~MyBase(){}
virtual int doStuff(int a) = 0;
};
Then you let the templated class inherit from it:
template <typename T>
class MyClass : MyBase {
public:
MyClass<T>(const std::string &file);
~MyClass<T>;
private:
T m_func;
int doStuff(int a) override {
return m_func(a);
}
};
Now you can have a pointer to MyBase
and inside the if-cases assign the concrete type. I hope you get the idea and will only give a rough sketch:
std::shared_ptr<MyBase> foo; // or perhaps a unique_ptr
if (metric == "A") {
foo = ... create MyClass<A>
} else if (metric == "B") {
...
}
foo->doStuff(3);
For the sake of completeness...your code didnt work, because in
if (metric == "A") {
MyClass<A> foo(filename);
}
the lifetime of foo
is limited to the scope of the if
case which ends with }
and you cannot access it outside.
PS: as all of the metrics have the same signature, I would have used a different approach that does not require MyClass
to be a template. Anyhow, MyClass
being a template seems to be a requirement.
PPS: Maybe it is just a matter of wording, but...
so what can I do in order to not instantiate every single type?
You can't do anything about that. Templates are instantiated at compile time. If you want to pick one instantiation at runtime you need to have them instantiated. In the above code (once you fill the holes) there will be an instantiation for each possible metric, but it is only one instance that gets created.
Upvotes: 2