Reputation: 15
I have a non-template class NC and a derived template class TC. I want to cast a pointer to NC, which is potentially a pointer to a TC instance, to a TC pointer. The actual types of the template are limited to e.g. bool, int, and string.
class NC {
...
}
template <typename T>
class TC: public NC {
private:
T value;
public:
...
void setValue(T value) {
this->value = value;
}
}
class UserValueProvider {
public:
int getValue() const { return 5; }
bool getValue() const { return true; }
string getValue() const { return "foobar"; }
}
void setUserValue(UserValueProvider *uvp, NC *obj) {
auto tobj = dynamic_cast< ? >(obj); // what goes here?
if(tobj)
tobj->setValue(uvp->getValue());
}
The obvious solution would be to perform 3 dynamic casts (for int, bool, and string) and call the setValue of the specialized instance. Yet I wonder whether there might be another solution, for the more specializations are possible the more dynamic casts would be needed and it would be more likely to forget one specialization.
Upvotes: 0
Views: 271
Reputation: 63134
One solution here is to flip the call around, and use a virtual function. But first, let's rewrite UserValueProvider::getValue
, as overloading solely on return types is forbidden.
class UserValueProvider {
template <class T> struct tag { };
int getValue(tag<int>) const { return 5; }
bool getValue(tag<bool>) const { return true; }
std::string getValue(tag<std::string>) const { return "foobar"; }
public:
template <class T>
T getValue() const {
return getValue(tag<T>{});
}
};
Now we can call uvp.getValue<T>()
to get the corresponding value. Next, add a virtual function to NC
and its derived classes:
class NC {
public:
virtual void setValueFrom(UserValueProvider &uvp) = 0;
};
template <typename T>
class TC: public NC {
private:
T value;
public:
void setValue(T value) {
this->value = value;
}
void setValueFrom(UserValueProvider &uvp) override {
setValue(uvp.getValue<T>());
}
};
And voilà, you can just pass your UserValueProvider
to your type-erased NC
and it will dispatch correctly.
void setUserValue(UserValueProvider *uvp, NC *obj) {
obj->setValueFrom(*uvp);
}
Upvotes: 0