All the time, I find myself doing something like this:
Animal *animal = ...
if (Cat *cat = dynamic_cast<Cat *>(animal)) {
...
}
else if (Dog *dog = dynamic_cast<Dog *>(animal)) {
...
}
else { assert(false); }
Once I see closures in C++11, I wonder, is something like this possible?
Animal *animal = ...
typecase(animal,
[](Cat *cat) {
...
},
[](Dog *dog) {
...
});
Implementing typecase should have been easy, but I keep running into a problem where it can't figure out the function's argument, so it can't know what to try to dynamic_cast to, because it's hard to deduce lambdas' parameters. Took a few days of searching google and SO, but finally figured it out, so I'll share my answer below.
template <typename T, typename B>
void action_if(B* value, std::function<void(T*)> action)
{
auto cast_value = dynamic_cast<T*>(value);
if (cast_value != nullptr)
{
action(cast_value);
}
}
Animal* animal = ...;
action_if<Cat>(animal, [](Cat* cat)
{
...
});
action_if<Dog>(animal, [](Dog* dog)
{
...
});
I don't have access to a C++11 compiler right this second to try this out, but I hope the idea is useful. Depending on how much type inference the compiler is capable of, you may or may not have to specify the case's type twice - I'm not C++11-pro enough to tell from looking at it.
I think it depends if you want do this at compile time or at run time. For compile time, Verdagon's answer is better, at runtime you can do something like this
class A {
};
class B {
};
void doForA() {
std::cout << "I'm A" << std::endl;
}
void doForB() {
std::cout << "I'm B" << std::endl;
}
int main() {
std::unordered_map<std::type_index, std::function<void(void)>> mytypes;
mytypes[typeid(A)] = doForA;
mytypes[typeid(B)] = doForB;
mytypes[typeid(A)]();
}
but both ways are wrong the virtual
keyword is here for this, you MUST do like Arie said or there is mistake in your architecture
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With